From a80735d7d389d622639e1026db8991476c8058f2 Mon Sep 17 00:00:00 2001 From: Olivier Date: Tue, 11 Oct 2022 23:37:12 +0900 Subject: [PATCH 01/15] Save the position of the last read page for comics --- cps/static/js/kthoom.js | 35 +++-- cps/templates/readcbr.html | 305 ++++++++++++++++++++----------------- cps/web.py | 2 +- 3 files changed, 186 insertions(+), 156 deletions(-) diff --git a/cps/static/js/kthoom.js b/cps/static/js/kthoom.js index 51dbadba..c587206f 100644 --- a/cps/static/js/kthoom.js +++ b/cps/static/js/kthoom.js @@ -70,8 +70,8 @@ var settings = { fitMode: kthoom.Key.B, theme: "light", direction: 0, // 0 = Left to Right, 1 = Right to Left - nextPage: 0, // 0 = Reset to Top, 1 = Remember Position - scrollbar: 1 // 0 = Hide Scrollbar, 1 = Show Scrollbar + nextPage: 0, // 0 = Reset to Top, 1 = Remember Position + scrollbar: 1 // 0 = Hide Scrollbar, 1 = Show Scrollbar }; kthoom.saveSettings = function() { @@ -130,7 +130,7 @@ var createURLFromArray = function(array, mimeType) { } if ((typeof URL !== "function" && typeof URL !== "object") || - typeof URL.createObjectURL !== "function") { + typeof URL.createObjectURL !== "function") { throw "Browser support for Object URLs is missing"; } @@ -186,8 +186,7 @@ function initProgressClick() { }); } -function loadFromArrayBuffer(ab) { - var lastCompletion = 0; +function loadFromArrayBuffer(ab, lastCompletion = 0) { const collator = new Intl.Collator('en', { numeric: true, sensitivity: 'base' }); loadArchiveFormats(['rar', 'zip', 'tar'], function() { // Open the file as an archive @@ -244,7 +243,7 @@ function updatePage() { // Mark the current page in the TOC $("#tocView a[data-page]") - // Remove the currently active thumbnail + // Remove the currently active thumbnail .removeClass("active") // Find the new one .filter("[data-page=" + (currentImage + 1) + "]") @@ -261,7 +260,7 @@ function updatePage() { } $("body").toggleClass("dark-theme", settings.theme === "dark"); - $("#mainContent").toggleClass("disabled-scrollbar", settings.scrollbar === 0); + $("#mainContent").toggleClass("disabled-scrollbar", settings.scrollbar === 0); kthoom.setSettings(); kthoom.saveSettings(); @@ -335,7 +334,7 @@ function setImage(url) { x.font = "50px sans-serif"; x.strokeStyle = "black"; x.fillText("Page #" + (currentImage + 1) + " (" + - imageFiles[currentImage].filename + ")", innerWidth / 2, 100); + imageFiles[currentImage].filename + ")", innerWidth / 2, 100); x.fillStyle = "black"; x.fillText("Is corrupt or not an image", innerWidth / 2, 200); @@ -418,9 +417,9 @@ function showPrevPage() { currentImage++; } else { updatePage(); - if (settings.nextPage === 0) { - $("#mainContent").scrollTop(0); - } + if (settings.nextPage === 0) { + $("#mainContent").scrollTop(0); + } } } @@ -431,9 +430,9 @@ function showNextPage() { currentImage--; } else { updatePage(); - if (settings.nextPage === 0) { - $("#mainContent").scrollTop(0); - } + if (settings.nextPage === 0) { + $("#mainContent").scrollTop(0); + } } } @@ -551,7 +550,7 @@ function init(filename) { request.responseType = "arraybuffer"; request.addEventListener("load", function() { if (request.status >= 200 && request.status < 300) { - loadFromArrayBuffer(request.response); + loadFromArrayBuffer(request.response, currentImage); } else { console.warn(request.statusText, request.responseText); } @@ -609,9 +608,9 @@ function init(filename) { $("#thumbnails").on("click", "a", function() { currentImage = $(this).data("page") - 1; updatePage(); - if (settings.nextPage === 0) { - $("#mainContent").scrollTop(0); - } + if (settings.nextPage === 0) { + $("#mainContent").scrollTop(0); + } }); // Fullscreen mode diff --git a/cps/templates/readcbr.html b/cps/templates/readcbr.html index 411e3fdd..6ab14a94 100644 --- a/cps/templates/readcbr.html +++ b/cps/templates/readcbr.html @@ -1,5 +1,6 @@ + @@ -17,78 +18,61 @@ - - - -
-
-
- Menu -
-
- {{ title | shortentitle }} -   –   - +
+
-
- -
- +
+ + + + diff --git a/cps/web.py b/cps/web.py index 51ff32b3..9793f01a 100755 --- a/cps/web.py +++ b/cps/web.py @@ -1561,7 +1561,7 @@ def read_book(book_id, book_format): title = title + " #" + '{0:.2f}'.format(book.series_index).rstrip('0').rstrip('.') log.debug("Start comic reader for %d", book_id) return render_title_template('readcbr.html', comicfile=all_name, title=title, - extension=fileExt) + extension=fileExt, bookmark=bookmark) log.debug("Selected book is unavailable. File does not exist or is not accessible") flash(_("Oops! Selected book is unavailable. File does not exist or is not accessible"), category="error") From 52172044e6bdb963c847e212f2d427d30ffd87c2 Mon Sep 17 00:00:00 2001 From: Ozzie Isaacs Date: Sat, 26 Aug 2023 20:12:52 +0200 Subject: [PATCH 04/15] Fix deprecation warnings --- cps/admin.py | 2 +- cps/editbooks.py | 5 ++--- cps/services/SyncToken.py | 5 ++--- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/cps/admin.py b/cps/admin.py index 93c1a3a9..045a9523 100644 --- a/cps/admin.py +++ b/cps/admin.py @@ -33,7 +33,7 @@ from functools import wraps from urllib.parse import urlparse from flask import Blueprint, flash, redirect, url_for, abort, request, make_response, send_from_directory, g, Response -from flask import Markup +from markupsafe import Markup from flask_login import login_required, current_user, logout_user from flask_babel import gettext as _ from flask_babel import get_locale, format_time, format_datetime, format_timedelta diff --git a/cps/editbooks.py b/cps/editbooks.py index 5a15740c..40f62713 100755 --- a/cps/editbooks.py +++ b/cps/editbooks.py @@ -25,16 +25,15 @@ from datetime import datetime import json from shutil import copyfile from uuid import uuid4 -from markupsafe import escape # dependency of flask +from markupsafe import escape, Markup # dependency of flask from functools import wraps -import re try: from lxml.html.clean import clean_html, Cleaner except ImportError: clean_html = None -from flask import Blueprint, request, flash, redirect, url_for, abort, Markup, Response +from flask import Blueprint, request, flash, redirect, url_for, abort, Response from flask_babel import gettext as _ from flask_babel import lazy_gettext as N_ from flask_babel import get_locale diff --git a/cps/services/SyncToken.py b/cps/services/SyncToken.py index c44841c1..3af0e276 100644 --- a/cps/services/SyncToken.py +++ b/cps/services/SyncToken.py @@ -19,10 +19,9 @@ import sys from base64 import b64decode, b64encode -from jsonschema import validate, exceptions, __version__ -from datetime import datetime, timezone +from jsonschema import validate, exceptions +from datetime import datetime -from urllib.parse import unquote from flask import json from .. import logger From b2a26a421c2c2e7163e5a71b33e2dd50f753f09b Mon Sep 17 00:00:00 2001 From: Ozzie Isaacs Date: Sat, 26 Aug 2023 20:26:01 +0200 Subject: [PATCH 05/15] Removed deprecation warning for sqlalchemy2.0 --- cps/db.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cps/db.py b/cps/db.py index f0295fe5..ceb692ec 100644 --- a/cps/db.py +++ b/cps/db.py @@ -663,7 +663,7 @@ class CalibreDB: cls.session_factory = scoped_session(sessionmaker(autocommit=False, autoflush=True, - bind=cls.engine)) + bind=cls.engine, future=True)) for inst in cls.instances: inst.init_session() From 885d914f18645ca7c15ffe8130bc8b9ae7d36d27 Mon Sep 17 00:00:00 2001 From: Ozzie Isaacs Date: Mon, 28 Aug 2023 18:06:32 +0200 Subject: [PATCH 06/15] Update tornado to 6.2 Remove unneeded imports from jsonschema for synctoken Update optional requirements Remove invalid direction arrows in comic reader --- cps/services/SyncToken.py | 6 +- cps/static/js/kthoom.js | 29 +++++++++- cps/templates/readcbr.html | 4 +- cps/tornado_wsgi.py | 110 +++++++++++++++++++------------------ optional-requirements.txt | 24 ++++---- requirements.txt | 10 ++-- 6 files changed, 107 insertions(+), 76 deletions(-) diff --git a/cps/services/SyncToken.py b/cps/services/SyncToken.py index c44841c1..bf31a7bc 100644 --- a/cps/services/SyncToken.py +++ b/cps/services/SyncToken.py @@ -19,10 +19,8 @@ import sys from base64 import b64decode, b64encode -from jsonschema import validate, exceptions, __version__ -from datetime import datetime, timezone - -from urllib.parse import unquote +from jsonschema import validate, exceptions +from datetime import datetime from flask import json from .. import logger diff --git a/cps/static/js/kthoom.js b/cps/static/js/kthoom.js index d955dfb1..072abcc0 100644 --- a/cps/static/js/kthoom.js +++ b/cps/static/js/kthoom.js @@ -177,12 +177,31 @@ kthoom.ImageFile = function(file) { } }; +function updateDirectionButtons(){ + $("#right").show(); + $("#left").show(); + if (currentImage == 0 ) { + if (settings.direction === 0) { + $("#left").hide(); + } else { + $("#right").hide(); + } + } + if ((currentImage + 1) >= Math.max(totalImages, imageFiles.length)) { + if (settings.direction === 0) { + $("#right").hide(); + } else { + $("#left").hide(); + } + } +} function initProgressClick() { $("#progress").click(function(e) { var offset = $(this).offset(); var x = e.pageX - offset.left; var rate = settings.direction === 0 ? x / $(this).width() : 1 - x / $(this).width(); currentImage = Math.max(1, Math.ceil(rate * totalImages)) - 1; + updateDirectionButtons(); updatePage(); }); } @@ -222,6 +241,11 @@ function loadFromArrayBuffer(ab) { // display first page if we haven't yet if (imageFiles.length === currentImage + 1) { + if (settings.direction === 0) { + $("#right").show(); + } else { + $("#left").show(); + } updatePage(); } } else { @@ -427,6 +451,7 @@ function showPrevPage() { } else { updatePage(); } + updateDirectionButtons(); } function showNextPage() { @@ -437,6 +462,7 @@ function showNextPage() { } else { updatePage(); } + updateDirectionButtons(); } function scrollCurrentImageIntoView() { @@ -677,6 +703,7 @@ function init(filename) { if(["hflip", "vflip", "rotateTimes"].includes(this.name)) { reloadImages(); } else if(this.name === "direction") { + updateDirectionButtons(); return updateProgress(); } @@ -726,7 +753,7 @@ function init(filename) { }, }); $(".mainImage").click(function(evt) { - // Firefox does not support offsetX/Y so we have to manually calculate + // Firefox does not support offsetX/Y, so we have to manually calculate // where the user clicked in the image. var mainContentWidth = $("#mainContent").width(); var mainContentHeight = $("#mainContent").height(); diff --git a/cps/templates/readcbr.html b/cps/templates/readcbr.html index a4ac3722..8b42cb79 100644 --- a/cps/templates/readcbr.html +++ b/cps/templates/readcbr.html @@ -77,8 +77,8 @@
-
- + + @@ -102,12 +102,12 @@ - + TestAnonymous 13 - 13 - 0 + 12 0 + 1 0 Detail @@ -197,11 +197,31 @@ - +
TestAnonymous - test_guest_change_visibility_series
- PASS + +
+ ERROR +
+ + + + @@ -234,11 +254,11 @@ - + TestBackupMetadata 22 - 22 - 0 + 21 + 1 0 0 @@ -302,11 +322,31 @@ - +
TestBackupMetadata - test_backup_change_book_publishing_date
- PASS + +
+ FAIL +
+ + + + @@ -1246,12 +1286,12 @@ AttributeError: 'bool' object has no attribute 'click' - + TestEditBooks 38 - 34 + 36 + 0 0 - 2 2 Detail @@ -1537,31 +1577,11 @@ AttributeError: 'bool' object has no attribute 'click' - +
TestEditBooks - test_upload_book_cb7
- -
- ERROR -
- - - - + PASS @@ -1647,31 +1667,11 @@ AttributeError: 'bool' object has no attribute 'click' - +
TestEditBooks - test_upload_cover_hdd
- -
- ERROR -
- - - - + PASS @@ -1815,11 +1815,11 @@ NameError: name 'details' is not defined - + TestEditBooksList 18 - 18 - 0 + 17 + 1 0 0 @@ -1937,11 +1937,31 @@ NameError: name 'details' is not defined - +
TestEditBooksList - test_bookslist_edit_series
- PASS + +
+ FAIL +
+ + + + @@ -2023,15 +2043,9 @@ NameError: name 'details' is not defined
Traceback (most recent call last):
-  File "/home/ozzie/Development/calibre-web-test/test/test_edit_books_metadata.py", line 209, in test_load_metadata
-    self.assertEqual(old_results, results)
-AssertionError: Lists differ: [] != [{'cover_element': <selenium.webdriver.rem[10121 chars]4/'}]
-
-Second list contains 20 additional elements.
-First extra element 0:
-{'cover_element': <selenium.webdriver.remote.webelement.WebElement (session="34034d2d-f804-47c1-b9ad-fcf09f75f812", element="6dfe81e2-4752-4f1f-bd33-9388d0d529c1")>, 'cover': 'https://books.google.com/books/content?id=Ub8TAQAAIAAJ&printsec=frontcover&img=1&zoom=1&source=gbs_api&fife=w800-h900', 'source': 'https://books.google.com/', 'author': 'Martin Vogt', 'publisher': '', 'title': 'Der Buchtitel in der römischen Poesie', 'title_link': 'https://books.google.com/books?id=Ub8TAQAAIAAJ'}
-
-Diff is 10795 characters long. Set self.maxDiff to None to see it.
+ File "/home/ozzie/Development/calibre-web-test/test/test_edit_books_metadata.py", line 167, in test_load_metadata + self.assertGreaterEqual(diff(BytesIO(cover), BytesIO(original_cover), delete_diff_file=True), 0.05) +AssertionError: 0.0 not greater than or equal to 0.05
@@ -2042,12 +2056,12 @@ Diff is 10795 characters long. Set self.maxDiff to None to see it. - + TestEditBooksOnGdrive 18 - 18 - 0 + 17 0 + 1 0 Detail @@ -2191,11 +2205,31 @@ Diff is 10795 characters long. Set self.maxDiff to None to see it. - +
TestEditBooksOnGdrive - test_edit_title
- PASS + +
+ ERROR +
+ + + + @@ -3374,13 +3408,13 @@ Diff is 10795 characters long. Set self.maxDiff to None to see it. TestOPDSFeed - 23 - 23 + 24 + 24 0 0 0 - Detail + Detail @@ -3559,7 +3593,7 @@ Diff is 10795 characters long. Set self.maxDiff to None to see it. -
TestOPDSFeed - test_opds_tags
+
TestOPDSFeed - test_opds_stats
PASS @@ -3568,7 +3602,7 @@ Diff is 10795 characters long. Set self.maxDiff to None to see it. -
TestOPDSFeed - test_opds_top_rated
+
TestOPDSFeed - test_opds_tags
PASS @@ -3577,7 +3611,7 @@ Diff is 10795 characters long. Set self.maxDiff to None to see it. -
TestOPDSFeed - test_opds_unicode_user
+
TestOPDSFeed - test_opds_top_rated
PASS @@ -3585,6 +3619,15 @@ Diff is 10795 characters long. Set self.maxDiff to None to see it. + +
TestOPDSFeed - test_opds_unicode_user
+ + PASS + + + + +
TestOPDSFeed - test_recently_added
@@ -3594,12 +3637,12 @@ Diff is 10795 characters long. Set self.maxDiff to None to see it. - - TestUploadPDF - 1 + + _FailedTest 1 0 0 + 1 0 Detail @@ -3608,11 +3651,37 @@ Diff is 10795 characters long. Set self.maxDiff to None to see it. - + -
TestUploadPDF - test_upload_invalid_pdf
+
_FailedTest - test_pdf_metadata
+ + +
+ ERROR +
+ + + - PASS @@ -3660,12 +3729,12 @@ Diff is 10795 characters long. Set self.maxDiff to None to see it. - + TestReader 6 - 6 - 0 + 5 0 + 1 0 Detail @@ -3674,11 +3743,47 @@ Diff is 10795 characters long. Set self.maxDiff to None to see it. - +
TestReader - test_comic_MACOS_files
- PASS + +
+ ERROR +
+ + + + @@ -5237,10 +5342,10 @@ Diff is 10795 characters long. Set self.maxDiff to None to see it. Total - 461 - 448 - 1 + 462 + 445 3 + 5 9   @@ -5311,13 +5416,13 @@ Diff is 10795 characters long. Set self.maxDiff to None to see it. flask-babel - 3.0.1 + 3.1.0 Basic Flask-Limiter - 3.3.1 + 3.4.1 Basic @@ -5371,19 +5476,19 @@ Diff is 10795 characters long. Set self.maxDiff to None to see it. pypdf - 3.7.1 + 3.15.4 Basic pytz - 2022.7.1 + 2023.3 Basic requests - 2.28.2 + 2.31.0 Basic @@ -5395,7 +5500,7 @@ Diff is 10795 characters long. Set self.maxDiff to None to see it. tornado - 6.2 + 6.3.3 Basic @@ -5731,7 +5836,7 @@ Diff is 10795 characters long. Set self.maxDiff to None to see it. From 5509d4598bbad41c6d9d0b1221d37962166c2b06 Mon Sep 17 00:00:00 2001 From: Ozzie Isaacs Date: Wed, 30 Aug 2023 20:23:40 +0200 Subject: [PATCH 08/15] Bugfix for showing series coatining only one book in list view containing having this book no series_index value set --- cps/web.py | 2 +- test/Calibre-Web TestSummary_Linux.html | 287 ++++++++++-------------- 2 files changed, 123 insertions(+), 166 deletions(-) diff --git a/cps/web.py b/cps/web.py index 95b1222c..4430dd90 100755 --- a/cps/web.py +++ b/cps/web.py @@ -1014,7 +1014,7 @@ def series_list(): func.max(db.Books.series_index), db.Books.id) .join(db.books_series_link).join(db.Series).filter(calibre_db.common_filters()) .group_by(text('books_series_link.series')) - .having(func.max(db.Books.series_index)) + .having(or_(func.max(db.Books.series_index), db.Books.series_index=="")) .order_by(order) .all()) return render_title_template('grid.html', entries=entries, folder='web.books_list', charlist=char_list, diff --git a/test/Calibre-Web TestSummary_Linux.html b/test/Calibre-Web TestSummary_Linux.html index b6ed61e8..808dca76 100644 --- a/test/Calibre-Web TestSummary_Linux.html +++ b/test/Calibre-Web TestSummary_Linux.html @@ -37,20 +37,20 @@
-

Start Time: 2023-08-28 19:42:24

+

Start Time: 2023-08-29 20:07:04

-

Stop Time: 2023-08-29 02:13:03

+

Stop Time: 2023-08-30 02:37:10

-

Duration: 5h 31 min

+

Duration: 5h 30 min

@@ -102,12 +102,12 @@ - + TestAnonymous 13 - 12 + 13 + 0 0 - 1 0 Detail @@ -197,31 +197,11 @@ - +
TestAnonymous - test_guest_change_visibility_series
- -
- ERROR -
- - - - + PASS @@ -254,12 +234,12 @@ IndexError: list index out of range - + TestBackupMetadata 22 - 21 + 19 1 - 0 + 2 0 Detail @@ -277,11 +257,42 @@ IndexError: list index out of range - +
TestBackupMetadata - test_backup_change_book_author
- PASS + +
+ FAIL +
+ + + + @@ -313,35 +324,30 @@ IndexError: list index out of range - +
TestBackupMetadata - test_backup_change_book_publisher
- PASS - - - - - - -
TestBackupMetadata - test_backup_change_book_publishing_date
-
- FAIL + ERROR
-
Traceback (most recent call last):
-  File "/home/ozzie/Development/calibre-web-test/test/test_edit_books_list.py", line 184, in test_bookslist_edit_series
+  File "/home/ozzie/Development/calibre-web-test/test/test_edit_books_list.py", line 185, in test_bookslist_edit_series
     self.assertEqual(3, len(elements))
-AssertionError: 3 != 2
+AssertionError: 3 != 4
@@ -2012,12 +2051,12 @@ AssertionError: 3 != 2 - + TestLoadMetadata 1 0 - 1 0 + 1 0 Detail @@ -2026,26 +2065,26 @@ AssertionError: 3 != 2 - +
TestLoadMetadata - test_load_metadata
- FAIL + ERROR
- From 4bbcec21e472902b02b71a3d689a3aeabda01d97 Mon Sep 17 00:00:00 2001 From: Ozzie Isaacs Date: Thu, 31 Aug 2023 11:42:55 +0200 Subject: [PATCH 09/15] Update test results --- test/Calibre-Web TestSummary_Linux.html | 227 +++++++----------------- 1 file changed, 67 insertions(+), 160 deletions(-) diff --git a/test/Calibre-Web TestSummary_Linux.html b/test/Calibre-Web TestSummary_Linux.html index 808dca76..77b834cc 100644 --- a/test/Calibre-Web TestSummary_Linux.html +++ b/test/Calibre-Web TestSummary_Linux.html @@ -37,20 +37,20 @@
-

Start Time: 2023-08-29 20:07:04

+

Start Time: 2023-08-30 20:29:50

-

Stop Time: 2023-08-30 02:37:10

+

Stop Time: 2023-08-31 03:01:14

-

Duration: 5h 30 min

+

Duration: 5h 31 min

@@ -234,12 +234,12 @@ - + TestBackupMetadata 22 - 19 - 1 - 2 + 22 + 0 + 0 0 Detail @@ -257,42 +257,11 @@ - +
TestBackupMetadata - test_backup_change_book_author
- -
- FAIL -
- - - - + PASS @@ -324,35 +293,11 @@ First extra element 1: - +
TestBackupMetadata - test_backup_change_book_publisher
- -
- ERROR -
- - - - + PASS @@ -375,35 +320,11 @@ FileNotFoundError: [Errno 2] No such file or directory: '/home/ozzie/Develop - + -
TestBackupMetadata - test_backup_change_book_seriesindex
- - -
- ERROR -
- - - +
TestBackupMetadata - test_backup_change_book_series_index
+ PASS @@ -1093,12 +1014,12 @@ FileNotFoundError: [Errno 2] No such file or directory: '/home/ozzie/Develop - + TestEditAdditionalBooks 20 - 17 + 18 + 0 0 - 1 2 Detail @@ -1215,31 +1136,11 @@ FileNotFoundError: [Errno 2] No such file or directory: '/home/ozzie/Develop - +
TestEditAdditionalBooks - test_upload_metadata_cb7
- -
- ERROR -
- - - - + PASS @@ -1854,11 +1755,11 @@ AttributeError: 'bool' object has no attribute 'click' - + TestEditBooksList 18 - 17 - 1 + 18 + 0 0 0 @@ -1976,31 +1877,11 @@ AttributeError: 'bool' object has no attribute 'click' - +
TestEditBooksList - test_bookslist_edit_series
- -
- FAIL -
- - - - + PASS @@ -2051,13 +1932,13 @@ AssertionError: 3 != 4 - + TestLoadMetadata 1 0 - 0 1 0 + 0 Detail @@ -2065,26 +1946,26 @@ AssertionError: 3 != 4 - +
TestLoadMetadata - test_load_metadata
- ERROR + FAIL
- From 444ac181f8da84bc6c880773a8a7831dbf0faba2 Mon Sep 17 00:00:00 2001 From: Ozzie Isaacs Date: Thu, 31 Aug 2023 16:51:06 +0200 Subject: [PATCH 10/15] more bookmark feature tornado fix for tornado <6.2 --- cps/static/js/kthoom.js | 159 +++++++++++++++++++++---------------- cps/templates/readcbr.html | 61 +++----------- cps/tornado_wsgi.py | 6 +- 3 files changed, 108 insertions(+), 118 deletions(-) diff --git a/cps/static/js/kthoom.js b/cps/static/js/kthoom.js index c1afb64c..3fbb22d3 100644 --- a/cps/static/js/kthoom.js +++ b/cps/static/js/kthoom.js @@ -133,7 +133,7 @@ var createURLFromArray = function(array, mimeType) { if ((typeof URL !== "function" && typeof URL !== "object") || typeof URL.createObjectURL !== "function") { - throw "Browser support for Object URLs is missing"; + throw "Browser support for Object URLs is missing"; } return URL.createObjectURL(blob); @@ -179,6 +179,8 @@ kthoom.ImageFile = function(file) { }; function updateDirectionButtons(){ + $("#right").show(); + $("#left").show(); if (currentImage == 0 ) { if (settings.direction === 0) { $("#right").show(); @@ -205,11 +207,12 @@ function initProgressClick() { var rate = settings.direction === 0 ? x / $(this).width() : 1 - x / $(this).width(); currentImage = Math.max(1, Math.ceil(rate * totalImages)) - 1; updateDirectionButtons(); + setBookmark(); updatePage(); }); } -function loadFromArrayBuffer(ab, lastCompletion = 0) { +function loadFromArrayBuffer(ab) { const collator = new Intl.Collator('en', { numeric: true, sensitivity: 'base' }); loadArchiveFormats(['rar', 'zip', 'tar'], function() { // Open the file as an archive @@ -244,12 +247,8 @@ function loadFromArrayBuffer(ab, lastCompletion = 0) { // display first page if we haven't yet if (imageFiles.length === currentImage + 1) { - if (settings.direction === 0) { - $("#right").show(); - } else { - $("#left").show(); - } - updatePage(lastCompletion); + updateDirectionButtons(); + updatePage(); } } else { totalImages--; @@ -264,13 +263,6 @@ function loadFromArrayBuffer(ab, lastCompletion = 0) { } function scrollTocToActive() { - // Scroll to the thumbnail in the TOC on page change - $("#tocView").stop().animate({ - scrollTop: $("#tocView a.active").position().top - }, 200); -} - -function updatePage() { $(".page").text((currentImage + 1 ) + "/" + totalImages); // Mark the current page in the TOC @@ -282,20 +274,19 @@ function updatePage() { // Set it to active .addClass("active"); + // Scroll to the thumbnail in the TOC on page change + $("#tocView").stop().animate({ + scrollTop: $("#tocView a.active").position().top + }, 200); +} + +function updatePage() { scrollTocToActive(); + scrollCurrentImageIntoView(); updateProgress(); pageDisplayUpdate(); setTheme(); - if (imageFiles[currentImage]) { - setImage(imageFiles[currentImage].dataURI); - } else { - setImage("loading"); - } - - $("body").toggleClass("dark-theme", settings.theme === "dark"); - $("#mainContent").toggleClass("disabled-scrollbar", settings.scrollbar === 0); - kthoom.setSettings(); kthoom.saveSettings(); } @@ -370,7 +361,6 @@ function setImage(url, _canvas) { img.onerror = function() { canvas.width = innerWidth - 100; canvas.height = 300; - updateScale(true); x.fillStyle = "black"; x.font = "50px sans-serif"; x.strokeStyle = "black"; @@ -424,8 +414,6 @@ function setImage(url, _canvas) { scrollTo(0, 0); x.drawImage(img, 0, 0); - updateScale(false); - canvas.style.display = ""; $("body").css("overflowY", ""); x.restore(); @@ -447,6 +435,7 @@ function showLeftPage() { } else { showNextPage(); } + setBookmark(); } function showRightPage() { @@ -455,6 +444,7 @@ function showRightPage() { } else { showPrevPage(); } + setBookmark(); } function showPrevPage() { @@ -464,9 +454,6 @@ function showPrevPage() { currentImage++; } else { updatePage(); - if (settings.nextPage === 0) { - $("#mainContent").scrollTop(0); - } } updateDirectionButtons(); } @@ -478,9 +465,6 @@ function showNextPage() { currentImage--; } else { updatePage(); - if (settings.nextPage === 0) { - $("#mainContent").scrollTop(0); - } } updateDirectionButtons(); } @@ -497,7 +481,7 @@ function scrollCurrentImageIntoView() { } } -function updateScale(clear) { +function updateScale() { var canvasArray = $("#mainContent > canvas"); var maxheight = innerHeight - 50; @@ -506,7 +490,7 @@ function updateScale(clear) { canvasArray.css("maxWidth", ""); canvasArray.css("maxHeight", ""); - if(!clear) { + if(settings.pageDisplay === 0) { canvasArray.addClass("hide"); pageDisplayUpdate(); } @@ -667,13 +651,23 @@ function drawCanvas() { $("#mainContent").append(canvasElement); } +function updateArrows() { + if ($('input[name="direction"]:checked').val() === "0") { + $("#prev_page_key").html("←"); + $("#next_page_key").html("→"); + } else { + $("#prev_page_key").html("→"); + $("#next_page_key").html("←"); + } +}; + function init(filename) { var request = new XMLHttpRequest(); request.open("GET", filename); request.responseType = "arraybuffer"; - request.addEventListener("load", function() { + request.addEventListener("load", function () { if (request.status >= 200 && request.status < 300) { - loadFromArrayBuffer(request.response, currentImage); + loadFromArrayBuffer(request.response); } else { console.warn(request.statusText, request.responseText); } @@ -687,18 +681,18 @@ function init(filename) { $(document).keydown(keyHandler); - $(window).resize(function() { + $(window).resize(function () { updateScale(); }); // Open TOC menu - $("#slider").click(function() { + $("#slider").click(function () { $("#sidebar").toggleClass("open"); $("#main").toggleClass("closed"); $(this).toggleClass("icon-menu icon-right"); // We need this in a timeout because if we call it during the CSS transition, IE11 shakes the page ¯\_(ツ)_/¯ - setTimeout(function() { + setTimeout(function () { // Focus on the TOC or the main content area, depending on which is open $("#main:not(.closed) #mainContent, #sidebar.open #tocView").focus(); scrollTocToActive(); @@ -706,12 +700,12 @@ function init(filename) { }); // Open Settings modal - $("#setting").click(function() { + $("#setting").click(function () { $("#settings-modal").toggleClass("md-show"); }); // On Settings input change - $("#settings input").on("change", function() { + $("#settings input").on("change", function () { // Get either the checked boolean or the assigned value var value = this.type === "checkbox" ? this.checked : this.value; @@ -720,43 +714,40 @@ function init(filename) { settings[this.name] = value; - if(["hflip", "vflip", "rotateTimes"].includes(this.name)) { + if (["hflip", "vflip", "rotateTimes"].includes(this.name)) { reloadImages(); - } else if(this.name === "direction") { + } else if (this.name === "direction") { updateDirectionButtons(); return updateProgress(); } - + updatePage(); - updateScale(false); + updateScale(); }); // Close modal - $(".closer, .overlay").click(function() { + $(".closer, .overlay").click(function () { $(".md-show").removeClass("md-show"); - $("#mainContent").focus(); // focus back on the main container so you use up/down keys without having to click on it + $("#mainContent").focus(); // focus back on the main container so you use up/down keys without having to click on it }); // TOC thumbnail pagination - $("#thumbnails").on("click", "a", function() { + $("#thumbnails").on("click", "a", function () { currentImage = $(this).data("page") - 1; updatePage(); - if (settings.nextPage === 0) { - $("#mainContent").scrollTop(0); - } }); // Fullscreen mode if (typeof screenfull !== "undefined") { - $("#fullscreen").click(function() { + $("#fullscreen").click(function () { screenfull.toggle($("#container")[0]); - // Focus on main container so you can use up/down keys immediately after fullscreen - $("#mainContent").focus(); + // Focus on main container so you can use up/down keys immediately after fullscreen + $("#mainContent").focus(); }); if (screenfull.raw) { var $button = $("#fullscreen"); - document.addEventListener(screenfull.raw.fullscreenchange, function() { + document.addEventListener(screenfull.raw.fullscreenchange, function () { screenfull.isFullscreen ? $button.addClass("icon-resize-small").removeClass("icon-resize-full") : $button.addClass("icon-resize-full").removeClass("icon-resize-small"); @@ -767,15 +758,15 @@ function init(filename) { // Focus the scrollable area so that keyboard scrolling work as expected $("#mainContent").focus(); - $("#mainContent").swipe( { - swipeRight:function() { + $("#mainContent").swipe({ + swipeRight: function () { showLeftPage(); }, - swipeLeft:function() { + swipeLeft: function () { showRightPage(); }, }); - $(".mainImage").click(function(evt) { + $(".mainImage").click(function (evt) { // Firefox does not support offsetX/Y, so we have to manually calculate // where the user clicked in the image. var mainContentWidth = $("#mainContent").width(); @@ -812,24 +803,30 @@ function init(filename) { }); // Scrolling up/down will update current image if a new image is into view (for Long Strip Display) - $("#mainContent").scroll(function(){ + $("#mainContent").scroll(function (event){ var scroll = $("#mainContent").scrollTop(); - if(settings.pageDisplay === 0) { + var viewLength = 0; + $(".mainImage").each(function(){ + viewLength += $(this).height(); + }); + if (settings.pageDisplay === 0) { // Don't trigger the scroll for Single Page - } else if(scroll > prevScrollPosition) { + } else if (scroll > prevScrollPosition) { //Scroll Down - if(currentImage + 1 < imageFiles.length) { - if(currentImageOffset(currentImage + 1) <= 1) { + if (currentImage + 1 < imageFiles.length) { + if (currentImageOffset(currentImage + 1) <= 1) { currentImage++; + console.log(Math.round(imageFiles.length / viewLength * scroll, 0)); scrollTocToActive(); updateProgress(); } } } else { //Scroll Up - if(currentImage - 1 > -1 ) { - if(currentImageOffset(currentImage - 1) >= 0) { + if (currentImage - 1 > -1) { + if (currentImageOffset(currentImage - 1) >= 0) { currentImage--; + console.log(Math.round(imageFiles.length / viewLength * scroll, 0)); scrollTocToActive(); updateProgress(); } @@ -844,3 +841,31 @@ function init(filename) { function currentImageOffset(imageIndex) { return $(".mainImage").eq(imageIndex).offset().top - $("#mainContent").position().top } + +function setBookmark() { + // get csrf_token + let csrf_token = $("input[name='csrf_token']").val(); + //This sends a bookmark update to calibreweb. + $.ajax(calibre.bookmarkUrl, { + method: "post", + data: { + csrf_token: csrf_token, + bookmark: currentImage + } + }).fail(function (xhr, status, error) { + console.error(error); + }); +} + +$(function() { + $('input[name="direction"]').change(function () { + updateArrows(); + }); + + $('#left').click(function () { + showLeftPage(); + }); + $('#right').click(function () { + showRightPage(); + }); +}); diff --git a/cps/templates/readcbr.html b/cps/templates/readcbr.html index 7a54e850..39786ec2 100644 --- a/cps/templates/readcbr.html +++ b/cps/templates/readcbr.html @@ -61,8 +61,8 @@
- - + + @@ -234,12 +234,12 @@ - + TestBackupMetadata 22 - 22 - 0 + 2 0 + 20 0 Detail @@ -248,29 +248,125 @@ - +
TestBackupMetadata - test_backup_all
- PASS + +
+ ERROR +
+ + + + - +
TestBackupMetadata - test_backup_change_book_author
- PASS + +
+ ERROR +
+ + + + - +
TestBackupMetadata - test_backup_change_book_description
- PASS + +
+ ERROR +
+ + + + @@ -284,146 +380,754 @@ - +
TestBackupMetadata - test_backup_change_book_language
- PASS + +
+ ERROR +
+ + + + - +
TestBackupMetadata - test_backup_change_book_publisher
- PASS + +
+ ERROR +
+ + + + - +
TestBackupMetadata - test_backup_change_book_publishing_date
- PASS + +
+ ERROR +
+ + + + - +
TestBackupMetadata - test_backup_change_book_rating
- PASS + +
+ ERROR +
+ + + + - + -
TestBackupMetadata - test_backup_change_book_series_index
+
TestBackupMetadata - test_backup_change_book_seriesindex
+ + +
+ ERROR +
+ + + - PASS - +
TestBackupMetadata - test_backup_change_book_tags
- PASS + +
+ ERROR +
+ + + + - +
TestBackupMetadata - test_backup_change_book_title
- PASS + +
+ ERROR +
+ + + + - +
TestBackupMetadata - test_backup_change_custom_Comment
- PASS + +
+ ERROR +
+ + + + - +
TestBackupMetadata - test_backup_change_custom_Enum
- PASS + +
+ ERROR +
+ + + + - +
TestBackupMetadata - test_backup_change_custom_bool
- PASS + +
+ ERROR +
+ + + + - +
TestBackupMetadata - test_backup_change_custom_categories
- PASS + +
+ ERROR +
+ + + + - +
TestBackupMetadata - test_backup_change_custom_date
- PASS - - - - - - -
TestBackupMetadata - test_backup_change_custom_float
+ +
+ ERROR +
+ + + - PASS - + -
TestBackupMetadata - test_backup_change_custom_int
+
TestBackupMetadata - test_backup_change_custom_float
- PASS - - + +
+ ERROR +
+ + + + + + + + + + +
TestBackupMetadata - test_backup_change_custom_int
+ + +
+ ERROR +
+ + + + + - + +
TestBackupMetadata - test_backup_change_custom_rating
- PASS + +
+ ERROR +
+ + + + - +
TestBackupMetadata - test_backup_change_custom_text
- PASS + +
+ ERROR +
+ + + + @@ -437,22 +1141,53 @@ - +
TestBackupMetadata - test_upload_book
- PASS + +
+ ERROR +
+ + + + - + TestBackupMetadataGdrive 1 - 1 0 0 + 1 0 Detail @@ -461,22 +1196,60 @@ - +
TestBackupMetadataGdrive - test_backup_gdrive
- PASS + +
+ ERROR +
+ + + + - + TestCli 13 - 13 - 0 - 0 + 10 + 2 + 1 0 Detail @@ -566,20 +1339,60 @@ - +
TestCli - test_logfile
- PASS + +
+ FAIL +
+ + + + - +
TestCli - test_no_database
- PASS + +
+ FAIL +
+ + + + @@ -593,11 +1406,44 @@ - +
TestCli - test_writeonly_static_files
- PASS + +
+ ERROR +
+ + + + @@ -711,11 +1557,11 @@ - + TestEbookConvertCalibre 15 - 15 - 0 + 14 + 1 0 0 @@ -725,11 +1571,31 @@ - +
TestEbookConvertCalibre - test_calibre_log
- PASS + +
+ FAIL +
+ + + + @@ -861,39 +1727,132 @@ - + TestEbookConvertCalibreGDrive - 6 - 6 - 0 - 0 + 7 + 4 + 1 + 2 0 - Detail + Detail - +
TestEbookConvertCalibreGDrive - test_convert_email
- PASS + +
+ ERROR +
+ + + + + + + + + + +
TestEbookConvertCalibreGDrive - test_convert_email
+ + +
+ ERROR +
+ + + + - +
TestEbookConvertCalibreGDrive - test_convert_failed_and_email
- PASS + +
+ FAIL +
+ + + + - +
TestEbookConvertCalibreGDrive - test_convert_only
@@ -902,7 +1861,7 @@ - +
TestEbookConvertCalibreGDrive - test_convert_parameter
@@ -911,7 +1870,7 @@ - +
TestEbookConvertCalibreGDrive - test_email_failed
@@ -920,7 +1879,7 @@ - +
TestEbookConvertCalibreGDrive - test_email_only
@@ -972,11 +1931,11 @@ - + TestEbookConvertGDriveKepubify 3 - 3 - 0 + 2 + 1 0 0 @@ -995,11 +1954,33 @@ - +
TestEbookConvertGDriveKepubify - test_convert_only
- PASS + +
+ FAIL +
+ + + + @@ -1014,12 +1995,12 @@ - + TestEditAdditionalBooks 20 - 18 - 0 - 0 + 11 + 2 + 5 2 Detail @@ -1028,29 +2009,111 @@ - +
TestEditAdditionalBooks - test_cbz_comicinfo
- PASS + +
+ ERROR +
+ + + + - +
TestEditAdditionalBooks - test_change_upload_formats
- PASS + +
+ ERROR +
+ + + + - +
TestEditAdditionalBooks - test_delete_book
- PASS + +
+ FAIL +
+ + + + @@ -1109,11 +2172,31 @@ - +
TestEditAdditionalBooks - test_title_sort
- PASS + +
+ FAIL +
+ + + + @@ -1189,11 +2272,44 @@ - +
TestEditAdditionalBooks - test_writeonly_path
- PASS + +
+ ERROR +
+ + + + @@ -1207,112 +2323,979 @@ - +
TestEditAdditionalBooks - test_xss_comment_edit
- PASS + +
+ ERROR +
+ + + + - +
TestEditAdditionalBooks - test_xss_custom_comment_edit
- PASS + +
+ ERROR +
+ + + + - - TestEditBooks - 38 - 36 + + _ErrorHolder + 10 0 0 - 2 + 10 + 0 - Detail + Detail - + -
TestEditBooks - test_download_book
+
tearDownClass (test_edit_additional_books)
- PASS - - - - - - -
TestEditBooks - test_edit_author
+ +
+ ERROR +
+ + + - PASS - + -
TestEditBooks - test_edit_category
+
tearDownClass (test_goodreads)
+ + +
+ ERROR +
+ + + - PASS - + -
TestEditBooks - test_edit_comments
+
tearDownClass (test_kobo_sync)
+ + +
+ ERROR +
+ + + - PASS - + -
TestEditBooks - test_edit_custom_bool
+
tearDownClass (test_kobo_sync_big)
+ + +
+ ERROR +
+ + + - PASS - + -
TestEditBooks - test_edit_custom_categories
+
tearDownClass (test_limiter)
+ + +
+ ERROR +
+ + + - PASS - + -
TestEditBooks - test_edit_custom_comment
+
setUpClass (test_logging)
+ + +
+ ERROR +
+ + + - PASS - + -
TestEditBooks - test_edit_custom_date
+
tearDownClass (test_pdf_metadata)
- PASS - - - + +
+ ERROR +
+ + + + + + + + + + +
tearDownClass (test_register)
+ + +
+ ERROR +
+ + + + + + + + + + +
tearDownClass (test_upload_epubs)
+ + +
+ ERROR +
+ + + + + + + + + + +
tearDownClass (test_user_load)
+ + +
+ ERROR +
+ + + + + + + + + + + TestEditBooks + 38 + 36 + 0 + 0 + 2 + + Detail + + + + + + + +
TestEditBooks - test_download_book
+ + PASS + + + + + + +
TestEditBooks - test_edit_author
+ + PASS + + + + + + +
TestEditBooks - test_edit_category
+ + PASS + + + + + + +
TestEditBooks - test_edit_comments
+ + PASS + + + + + + +
TestEditBooks - test_edit_custom_bool
+ + PASS + + + + + + +
TestEditBooks - test_edit_custom_categories
+ + PASS + + + + + + +
TestEditBooks - test_edit_custom_comment
+ + PASS + + + + + + +
TestEditBooks - test_edit_custom_date
+ + PASS + + - + +
TestEditBooks - test_edit_custom_float
@@ -1321,7 +3304,7 @@ - +
TestEditBooks - test_edit_custom_int
@@ -1330,7 +3313,7 @@ - +
TestEditBooks - test_edit_custom_rating
@@ -1339,7 +3322,7 @@ - +
TestEditBooks - test_edit_custom_single_select
@@ -1348,7 +3331,7 @@ - +
TestEditBooks - test_edit_custom_text
@@ -1357,7 +3340,7 @@ - +
TestEditBooks - test_edit_language
@@ -1366,7 +3349,7 @@ - +
TestEditBooks - test_edit_publisher
@@ -1375,7 +3358,7 @@ - +
TestEditBooks - test_edit_publishing_date
@@ -1384,7 +3367,7 @@ - +
TestEditBooks - test_edit_rating
@@ -1393,7 +3376,7 @@ - +
TestEditBooks - test_edit_series
@@ -1402,7 +3385,7 @@ - +
TestEditBooks - test_edit_title
@@ -1411,19 +3394,19 @@ - +
TestEditBooks - test_rename_upper_lowercase
- SKIP + SKIP
-