summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Dolgov <[email protected]>2024-02-19 20:53:47 +0300
committerAndrew Dolgov <[email protected]>2024-02-19 20:53:47 +0300
commitfbbcdb168b87421d754382f8aef5ab5fdfc72713 (patch)
tree95fdb06a2374f3c1b0c462419a8fc0d840263d7e
parent3507ee032f6426b9838a3e9a3dd997d5f33374d4 (diff)
stop bothering with mtime to detect cache refresh need
-rw-r--r--dist/app.min.js2
-rw-r--r--index.php8
-rw-r--r--js/app.js8
3 files changed, 4 insertions, 14 deletions
diff --git a/dist/app.min.js b/dist/app.min.js
index 4d089b3..e6f22b2 100644
--- a/dist/app.min.js
+++ b/dist/app.min.js
@@ -1 +1 @@
-"use strict";$.urlParam=function(t){try{const e=new RegExp("[?&]"+t+"=([^&#]*)").exec(window.location.href);return decodeURIComponent(e[1].replace(/\+/g," "))||0}catch(t){return 0}};const Cookie={set:function(t,e,o){const a=new Date;a.setTime(a.getTime()+1e3*o);const n="expires="+a.toUTCString();document.cookie=t+"="+encodeURIComponent(e)+"; "+n},get:function(t){t+="=";const e=document.cookie.split(";");for(let o=0;o<e.length;o++){let a=e[o];for(;" "==a.charAt(0);)a=a.substring(1);if(0==a.indexOf(t))return decodeURIComponent(a.substring(t.length,a.length))}return""},delete:function(t){document.cookie=t+"=; expires=Thu, 01-Jan-1970 00:00:01 GMT"}},App={_dl_progress_timeout:!1,index_mode:"",last_mtime:-1,cached_urls:[],version:"UNKNOWN",csrf_token:"",init:function(){let t=0;this.csrf_token=Cookie.get("epube_csrf_token"),console.log("setting prefilter for token",this.csrf_token),$.ajaxPrefilter((function(t,e,o){if("post"!==e.type||"post"!==t.type)return;const a=typeof e.data;"object"==a?t.data=$.param($.extend(e.data,{csrf_token:App.csrf_token})):"string"==a&&(t.data=e.data+"&csrf_token="+encodeURIComponent(App.srf_token)),console.log(">>>",t)})),"undefined"!=typeof EpubeApp&&($(".navbar").hide(),$(".epube-app-filler").show(),$(".separate-search").show(),"favorites"==$.urlParam("mode")?EpubeApp.setPage("PAGE_FAVORITES"):EpubeApp.setPage("PAGE_LIBRARY")),App.initNightMode(),"serviceWorker"in navigator?(navigator.serviceWorker.addEventListener("message",(function(e){"refresh-started"==e.data&&(console.log("cache refresh started"),t=0,$(".dl-progress").fadeIn().text("Loading, please wait...")),e.data&&0==e.data.indexOf("refreshed:")&&(++t,$(".dl-progress").fadeIn().text("Updated "+t+" files...")),"refresh-finished"==e.data&&(localforage.setItem("epube.cache-timestamp",App.last_mtime),localforage.setItem("epube.cache-version",App.version),window.location.reload())})),App.showCovers(),App.Offline.markBooks(),App.refreshCache()):$(".container-main").addClass("alert alert-danger").html("Service worker support missing in browser (are you using plain HTTP?).")},logout:function(){$.post("backend.php",{op:"logout"}).then(()=>{window.location.reload()})},showSummary:function(t){const e=t.getAttribute("data-book-id");return $.post("backend.php",{op:"getinfo",id:e},(function(t){const e=t.comment?t.comment:"No description available";$("#summary-modal .modal-title").html(t.title),$("#summary-modal .book-summary").html(e),$("#summary-modal").modal()})),!1},showCovers:function(){$("img[data-book-id]").each((t,e)=>{if((e=$(e)).attr("data-cover-link")){const t=$("<img>").on("load",(function(){e.css("background-image","url("+e.attr("data-cover-link")+")").fadeIn(),t.attr("src",null)})).attr("src",e.attr("data-cover-link"))}})},toggleFavorite:function(t){const e=t.getAttribute("data-book-id");return("0"==t.getAttribute("data-is-fav")||confirm("Remove favorite?"))&&$.post("backend.php",{op:"togglefav",id:e},(function(o){if(o){let a="[Error]";0==o.status?a="Add to favorites":1==o.status&&(a="Remove from favorites"),$(t).html(a).attr("data-is-fav",o.status),"favorites"==App.index_mode&&0==o.status&&$("#cell-"+e).remove()}})),!1},refreshCache:function(t){"serviceWorker"in navigator?localforage.getItem("epube.cache-timestamp").then((function(e){console.log("stamp",e,"last mtime",App.last_mtime,"version",App.version),(t||e!=App.last_mtime)&&(console.log("asking worker to refresh cache"),navigator.serviceWorker.controller?navigator.serviceWorker.controller.postMessage({msg:"refresh-cache",urls:App.cached_urls}):localforage.getItem("epube.initial-load-done").then((function(t){console.log("initial load done",t),t?$(".dl-progress").show().addClass("alert-danger").html("Could not communicate with service worker. Try reloading the page."):localforage.setItem("epube.initial-load-done",!0).then((function(){$(".dl-progress").show().addClass("alert-info").html("Page will reload to activate service worker..."),window.setTimeout((function(){window.location.reload()}),3e3)}))})))})):$(".dl-progress").show().addClass("alert-danger").html("Could not communicate with service worker. Try reloading the page.")},isOnline:function(){return"undefined"!=typeof EpubeApp&&void 0!==EpubeApp.isOnline?EpubeApp.isOnline():navigator.onLine},appCheckOffline:function(){EpubeApp.setOffline(!App.isOnline)},initNightMode:function(){if("undefined"==typeof EpubeApp){if(window.matchMedia){const t=window.matchMedia("(prefers-color-scheme: dark)");t.addEventListener("change",()=>{App.applyNightMode(t.matches)}),App.applyNightMode(t.matches)}}else App.applyNightMode(EpubeApp.isNightMode())},applyNightMode:function(t){console.log("night mode changed to",t),$("#theme_css").attr("href","lib/bootstrap/v3/css/"+(t?"theme-dark.min.css":"bootstrap-theme.min.css"))},Offline:{init:function(){"undefined"!=typeof EpubeApp&&($(".navbar").hide(),$(".epube-app-filler").show(),EpubeApp.setPage("PAGE_OFFLINE")),App.initNightMode();const t=$.urlParam("query");t&&$(".search_query").val(t),App.Offline.populateList()},get:function(t,e){console.log("offline cache: "+t),$.post("backend.php",{op:"getinfo",id:t},(function(o){if(o){const a="epube-book."+t;localforage.setItem(a,o).then((function(o){console.log(a+" got data");const n=[];n.push(fetch("backend.php?op=download&id="+o.epub_id,{credentials:"same-origin"}).then((function(t){200==t.status&&(console.log(a+" got book"),e(),localforage.setItem(a+".book",t.blob()))}))),n.push(fetch("backend.php?op=getpagination&id="+o.epub_id,{credentials:"same-origin"}).then((function(t){200==t.status&&(console.log(a+" got pagination"),t.text().then((function(t){localforage.setItem(a+".locations",JSON.parse(t))})))}))),n.push(fetch("backend.php?op=getlastread&id="+o.epub_id,{credentials:"same-origin"}).then((function(t){200==t.status&&(console.log(a+" got lastread"),t.text().then((function(t){localforage.setItem(a+".lastread",JSON.parse(t))})))}))),o.has_cover&&n.push(fetch("backend.php?op=cover&id="+t,{credentials:"same-origin"}).then((function(t){200==t.status&&(console.log(a+" got cover"),localforage.setItem(a+".cover",t.blob()))}))),Promise.all(n).then((function(){$(".dl-progress").show().html("Finished downloading <b>"+o.title+"</b>"),window.clearTimeout(App._dl_progress_timeout),App._dl_progress_timeout=window.setTimeout((function(){$(".dl-progress").fadeOut()}),5e3)}))}))}}))},getAll:function(){confirm("Download all books on this page?")&&$(".row > div").each((function(t,e){const o=$(e).attr("id").replace("cell-",""),a=$(e).find(".offline_dropitem")[0];if(o){const t="epube-book."+o;localforage.getItem(t).then((function(t){t||App.Offline.get(o,(function(){App.Offline.mark(a)}))}))}}))},markBooks:function(){const t=$(".offline_dropitem");$.each(t,(function(t,e){App.Offline.mark(e)}))},mark:function(t){const e=t.getAttribute("data-book-id"),o="epube-book."+e;localforage.getItem(o).then((function(o){o?(t.onclick=function(){return App.Offline.remove(e,(function(){App.Offline.mark(t)})),!1},t.innerHTML="Remove offline data"):(t.onclick=function(){return App.Offline.get(e,(function(){App.Offline.mark(t)})),!1},t.innerHTML="Make available offline")}))},removeFromList:function(t){const e=t.getAttribute("data-book-id");return App.Offline.remove(e,(function(){$("#cell-"+e).remove()}))},remove:function(t,e){if(confirm("Remove download?")){const o="epube-book."+t,a=[];console.log("offline remove: "+t),localforage.iterate((function(t,e){e.match(o)&&a.push(localforage.removeItem(e))})),Promise.all(a).then((function(){window.setTimeout((function(){e()}),500)}))}},search:function(){const t=$(".search_query").val();return localforage.setItem("epube.search-query",t).then((function(){App.Offline.populateList()})),!1},removeAll:function(){if(confirm("Remove all downloaded books?")){const t=[];localforage.iterate((function(e,o){o.match("epube-book")&&t.push(localforage.removeItem(o))})),Promise.all(t).then((function(){window.setTimeout((function(){App.Offline.populateList()}),500)}))}},showSummary:function(t){const e=t.getAttribute("data-book-id");return localforage.getItem("epube-book."+e).then((function(t){const e=t.comment?t.comment:"No description available";$("#summary-modal .modal-title").html(t.title),$("#summary-modal .book-summary").html(e),$("#summary-modal").modal()})),!1},populateList:function(){let t=$.urlParam("query");t&&(t=t.toLowerCase());const e=$("#books_container");e.html(""),localforage.iterate((function(o,a){a.match(/epube-book\.\d{1,}$/)&&Promise.all([localforage.getItem(a),localforage.getItem(a+".cover"),localforage.getItem(a+".lastread"),localforage.getItem(a+".book")]).then((function(o){if(o[0]&&o[3]){const a=o[0];if(t){if(!(a.series_name&&a.series_name.toLowerCase().match(t)||a.title&&a.title.toLowerCase().match(t)||a.author_sort&&a.author_sort.toLowerCase().match(t)))return}let n=!1;o&&o[1]&&(n=URL.createObjectURL(o[1]));let i=!1,r=!1;const l=o[2];l&&(i=l.page>0,r=l.total>0&&l.total-l.page<5);const s=r?"read":"",c=i?"in_progress":"",d=a.series_name?`<div><a class="series_link" href="#">${a.series_name+" ["+a.series_index+"]"}</a></div>`:"",f=$(`<div class="col-xxs-6 col-xs-4 col-sm-3 col-md-2" id="cell-${a.id}">\n\t\t\t\t\t\t\t<a class="thumbnail ${s}" href="read.html?id=${a.epub_id}&b=${a.id}">\n\t\t\t\t\t\t\t\t<img style="display : none">\n\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t\t<div class="caption">\n\t\t\t\t\t\t\t\t<div><a class="${c}" href="read.html?id=${a.epub_id}&b=${a.id}">${a.title}</a></div>\n\t\t\t\t\t\t\t\t<div><a class="author_link" href="#">${a.author_sort}</a></div>\n\t\t\t\t\t\t\t\t${d}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<div class="dropdown" style="white-space : nowrap">\n\t\t\t\t\t\t\t\t<a href="#" data-toggle="dropdown" role="button">More...<span class="caret"></span></a>\n\t\t\t\t\t\t\t\t<ul class="dropdown-menu">\n\t\t\t\t\t\t\t\t\t<li><a href="#" data-book-id="${a.id}" onclick="return App.Offline.showSummary(this)">Summary</a></li>\n\t\t\t\t\t\t\t\t\t<li><a href="#" data-book-id="${a.id}" onclick="App.Offline.removeFromList(this)">Remove offline data</a></li>\n\t\t\t\t\t\t\t\t</ul>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>`);n?f.find("img").css("background-image","url("+n+")").fadeIn():f.fadeIn(),f.find(".series_link").attr("title",a.series_name+" ["+a.series_index+"]").attr("href","offline.html?query="+encodeURIComponent(a.series_name)),f.find(".author_link").attr("title",a.author_sort).attr("href","offline.html?query="+encodeURIComponent(a.author_sort)),e.append(f)}}))}))}}},DEFAULT_FONT_SIZE=16,DEFAULT_FONT_FAMILY="Arial",DEFAULT_LINE_HEIGHT=140,MIN_LENGTH_TO_JUSTIFY=32,LOCATION_DIVISOR=10,PAGE_RESET_PROGRESS=-1,CACHE_PREFIX="epube",CACHE_NAME="epube-v3";Promise.allSettled=Promise.allSettled||(t=>Promise.all(t.map(t=>t.then(t=>({status:"fulfilled",value:t})).catch(t=>({status:"rejected",reason:t})))));const Reader={csrf_token:"",last_stored_cfi:"",startup_finished:!1,hyphenate:{},init:function(){this.csrf_token=Cookie.get("epube_csrf_token"),console.log("setting prefilter for token",this.csrf_token),$.ajaxPrefilter((function(t,e){if("post"!==e.type||"post"!==t.type)return;const o=typeof e.data;"object"==o?t.data=$.param($.extend(e.data,{csrf_token:Reader.csrf_token})):"string"==o&&(t.data=e.data+"&csrf_token="+encodeURIComponent(Reader.srf_token)),console.log(">>>",t)})),$(document).on("keyup",(function(t){Reader.hotkeyHandler(t)})),$("#left").on("mouseup",(function(){Reader.Page.prev()})),$("#right").on("mouseup",(function(){Reader.Page.next()})),Reader.Loader.init()},onOfflineModeChanged:function(t){if(console.log("onOfflineModeChanged",t),!t&&window.book){const t=window.book;console.log("we're online, storing lastread");const e=t.rendition.currentLocation().start.cfi,o=parseInt(100*t.locations.percentageFromCfi(e));$.post("backend.php",{op:"storelastread",id:$.urlParam("id"),page:o,cfi:e,timestamp:(new Date).getTime()},(function(){})).fail((function(t){t&&401==t.status&&(window.location="index.php")}))}},initSecondStage:async function(){"undefined"!=typeof EpubeApp?EpubeApp.setPage("PAGE_READER"):($(window).on("online",(function(){Reader.onOfflineModeChanged(!1)})),$(window).on("offline",(function(){Reader.onOfflineModeChanged(!0)}))),Reader.applyTheme();if(!await localforage.getItem(Reader.cacheId())){const t=$.urlParam("b");console.log("requesting bookinfo for book",t);try{const e=await $.post("backend.php",{op:"getinfo",id:t});if(e.has_cover){const e=await fetch("backend.php?op=cover&id="+t);e.ok&&await localforage.setItem(Reader.cacheId("cover"),e.blob())}await localforage.setItem(Reader.cacheId(),e),console.log("bookinfo saved")}catch(t){return void $(".loading-message").html(`Unable to load book info.<br/><small>${t.responseText}</small>`)}}console.log("trying to load book...");let t=await localforage.getItem(Reader.cacheId("book"));if(!t){console.log("local data not found, loading from network..."),$(".loading-message").html("Downloading book…");const e=await fetch("backend.php?op=download&id="+$.urlParam("id"));if(!e.ok)return void $(".loading-message").html("Unable to download book: "+e.status);if(t=await e.blob(),!t)return void $(".loading-message").html("Unable to get book blob data.");await localforage.setItem(Reader.cacheId("book"),t),console.log("saved local data for book")}const e=new FileReader;e.onload=function(){try{Reader.openBookData(this.result)}catch(t){console.error(t),$(".loading-message").html("Unable to load book blob: "+t)}},e.onerror=t=>{console.log("filereader error",t),$(".loading-message").html("Unable to open book.<br/><small>"+t+"</small>")},e.readAsArrayBuffer(t)},openBookData:async function(t){const e=ePub();window.book=e;try{await e.open(t)}catch(t){return console.error(t),void $(".loading-message").html("Unable to open book.<br/><small>"+t.message+"</small>")}await e.ready,console.log("book is ready"),await Reader.showBookInfo(e),await Reader.loadLocations(e);const o=e.renderTo("reader",{width:"100%",height:"100%",allowScriptedContent:!0,minSpreadWidth:961});$(".location").click((async function(){const t=Math.floor(o.currentLocation().start.location/10),a=Math.floor(e.locations.length()/10),n=prompt("Jump to location [1-"+a+"]",t);n&&await o.display(e.locations._locations[10*n])}));await localforage.getItem("epube.enable-hyphens")&&(Reader.hyphenate.en=createHyphenator(hyphenationPatternsEnUs,{html:!0}),Reader.hyphenate.ru=createHyphenator(hyphenationPatternsRu,{html:!0})),Reader.applyStyles(!0),console.log("book displayed"),Reader.initRenditionHooks(e,o),Reader.initModals(),Reader.initToc(e),Reader.initStyleHooks(e),await Reader.Page.openLastRead(),console.log("startup finished"),Reader.startup_finished=!0},showBookInfo:async function(t){const e=await localforage.getItem(Reader.cacheId());let o,a;if(e)o=e.title,a=e.author_sort;else{const e=t.package.metadata;o=e.title,a=e.creator}document.title=o+" – "+a+" – The Epube",$(".title").text(o).attr("title",o+" – "+a),"undefined"!=typeof EpubeApp&&(EpubeApp.setTitle(o),EpubeApp.showActionBar(!1))},loadLocations:async function(t){let e=await localforage.getItem(Reader.cacheId("locations"));if(e&&"string"==typeof e[0]){console.log("loading local locations...");try{return void await t.locations.load(e)}catch(t){console.warn(t)}}if(App.isOnline()){console.log("downloading locations..."),$(".loading-message").html("Downloading locations…");const o=await fetch("backend.php?op=getpagination&id="+$.urlParam("id"));if(o.ok&&(console.log("got locations from server"),e=await o.json(),e&&"string"==typeof e[0])){console.log("saving locations locally..."),await localforage.setItem(Reader.cacheId("locations"),e);try{return void t.locations.load(e)}catch(t){console.warn(t)}}}$(".loading-message").html("Preparing locations…"),e=await t.locations.generate(100),$.post("backend.php",{op:"storepagination",id:$.urlParam("id"),payload:JSON.stringify(e),total:100}),await localforage.setItem(Reader.cacheId("locations"),e)},initRenditionHooks:function(t,e){e.hooks.content.register(async t=>{t.on("linkClicked",t=>{console.log("linkClicked",t),Reader.Page.blockLastReadUpdate(),-1==t.indexOf("://")&&($(".prev_location_btn").attr("data-location-cfi",e.currentLocation().start.cfi).show(),window.setTimeout((function(){Reader.showUI(!0)}),50))});const o=window.location.href.match(/^.*\//)[0];"undefined"!=typeof EpubeApp?$(t.document.head).append($('<link type="text/css" rel="stylesheet" media="screen" href="/assets/android.css" />')):$(t.document.head).append($("<style type='text/css'>").text(Reader.generateFontsCss(o)));const a=["dist/app-libs.min.js","dist/reader_iframe.min.js"];for(let e=0;e<a.length;e++){const n=t.document.createElement("script");n.type="text/javascript",n.text=Reader.Loader._res_data[o+a[e]],t.document.head.appendChild(n)}$(t.document.head).append($("<style type='text/css'>").text(Reader.Loader._res_data[o+"dist/reader_iframe.min.css"]));const n=await localforage.getItem("epube.theme")||"default";$(t.document).find("body").attr("class","undefined"!=typeof EpubeApp?"is-epube-app":"").addClass("theme-"+n)}),e.on("keyup",t=>{Reader.hotkeyHandler(t)}),e.on("rendered",(function(){$(".chapter").html($("<span>").addClass("glyphicon glyphicon-th-list")),setTimeout(()=>{Reader.Page._moved_next=0},150),Reader.applyTheme(),Reader.resizeSideColumns();try{const o=e.currentLocation();if(o.start){const e=t.canonical(o.start.href);let a=!1;$.each(Reader.flattenToc(t),(function(o,n){t.spine.get(n.href).canonical!=e||(a=n)})),a&&a.label&&$(".chapter").append("&nbsp;"+a.label.trim()+" | "),Reader.generateTocBar(t,Reader.flattenToc(t))}}catch(t){console.warn(t)}})),e.on("relocated",e=>Reader.Page.onRelocated(t,e))},initModals:function(){$("#settings-modal").on("shown.bs.modal",(async function(){const t=await localforage.getItem(Reader.cacheId("lastread"));t&&t.cfi&&$(".lastread_input").val(t.page+"%").attr("title","[local] "+t.cfi),navigator.onLine&&$.post("backend.php",{op:"getlastread",id:$.urlParam("id")},t=>{$(".lastread_input").val(t.page+"%").attr("title","[remote] "+t.cfi)}),$(".enable_hyphens_checkbox").attr("checked",await localforage.getItem("epube.enable-hyphens")).off("click").on("click",(function(t){localforage.setItem("epube.enable-hyphens",t.target.checked),confirm("Toggling hyphens requires page reload. Reload now?")&&window.location.reload()})),"undefined"!=typeof EpubeApp?$(".keep_ui_checkbox").parent().parent().hide():$(".keep_ui_checkbox").attr("checked",await localforage.getItem("epube.keep-ui-visible")).off("click").on("click",(function(t){localforage.setItem("epube.keep-ui-visible",t.target.checked)}));const e=await localforage.getItem("epube.enable-column-hacks");$(".enable_column_hacks_checkbox").attr("checked",e).off("click").on("click",(function(t){localforage.setItem("epube.enable-column-hacks",t.target.checked)}));const o=await localforage.getItem("epube.cache-timestamp"),a=await localforage.getItem("epube.cache-version");$(".last-mod-timestamp").html(`${a}\n\t\t\t\t&mdash; ${parseInt(o)?new Date(1e3*o).toLocaleString("en-GB"):"Unknown"}\n\t\t\t\t(${App.isOnline()?"<span class='text-success'>Online</span>":"<span class='text-danger'>Offline</span>"})\n\t\t\t\t`),$(".font_family").val(await localforage.getItem("epube.fontFamily")||"Arial"),$(".theme_name").val(await localforage.getItem("epube.theme")||"default");const n=$(".font_size").html("");for(let t=10;t<=32;t++){const e=$("<option>").val(t).html(t+" px");n.append(e)}n.val(await localforage.getItem("epube.fontSize")||16);const i=$(".line_height").html("");for(let t=100;t<=220;t+=10){const e=$("<option>").val(t).html(t+"%");i.append(e)}i.val(await localforage.getItem("epube.lineHeight")||140)})),$("#dict-modal").on("shown.bs.modal",(function(){$(".dict_result").scrollTop(0)})),$(".dict_search_btn").on("click",(function(){$("#dict-modal").modal("hide"),window.open("https://duckduckgo.com/?q="+$(".dict_query").val())})),$(".wiki_search_btn").on("click",(function(){$(".dict_result").html("Loading, please wait..."),$.post("backend.php",{op:"wikisearch",query:$(".dict_query").val()}).then(t=>{try{console.log("wikisearch resp",t);let e="";$.each(t.query.pages,(t,o)=>{e+=o.extract}),$(".dict_result").html(e&&"undefined"!=e?e:"No definition found for "+$(".dict_query").val()+".")}catch(t){console.error(t),$(".dict_result").text("Error while processing data: "+t)}}).fail(t=>{console.error(t),$(".dict_result").text("Error while retrieving data.")})}))},initToc:function(t){function e(e){try{const o=t.spine.get(e).cfiBase,a=t.locations._locations.find((function(t){return-1!=t.indexOf(o)}));return parseInt(window.book.locations.locationFromCfi(a)/10)}catch(t){console.warn(t)}return""}$("#toc-modal").on("shown.bs.modal",(function(){const o=t.navigation.toc,a=$(".toc_list");a.html(""),$.each(o,(function(o,n){try{const o=$("<a>").attr("href","#").html("<b class='pull-right'>"+e(n.href)+"</b>"+n.label).attr("data-href",n.href).click((function(){t.rendition.display(o.attr("data-href"))}));a.append($("<li>").append(o)),function o(a,n,i){if(3==i)return!1;if(a.subitems){const r=$("<ul class='toc_sublist list-unstyled'>");$.each(a.subitems,(function(a,n){const l=$("<a>").attr("href","#").html("<b class='pull-right'>"+e(n.href)+"</b>"+n.label).attr("data-href",n.href).click((function(){t.rendition.display(l.attr("data-href"))}));r.append($("<li>").append(l)),o(n,r,i+1)})),n.append(r)}}(n,a,0)}catch(t){console.warn(t)}})),a.children().length<=1&&(a.html(""),$.each(t.spine.items,(function(e,o){const n=$("<a>").attr("href","#").attr("title",o.url).html("Section "+(e+1)).attr("data-href",o.href).click((function(){t.rendition.display(n.attr("data-href"))}));a.append($("<li>").append(n))})))}))},initStyleHooks:function(t){t.spine.hooks.content.register((function(t){$(t).find("p").filter((t,e)=>$(e).text().length>=32?e:null).css("text-align","justify"),$(t).find("html").attr("class",""),$(t).find("pre").css("white-space","pre-wrap"),$(t).find("a, p, span, em, i, strong, b, body, header, section, div, big, small, table, tr, td, ul, ol, li").attr("class","").css("font-family","inherit").css("font-size","inherit").css("line-height","inherit").css("color","").css("border","none ! important").css("background","").css("background-color","").attr("width","").attr("height",""),$(t).find("h1, h2, h3, h4, h5").attr("class","").css("font-family","inherit").css("color","").css("border","none ! important").css("background","").css("background-color",""),void 0!==Reader.hyphenate.en&&$(t).find("p, div").each((t,e)=>{(e=$(e)).html(Reader.hyphenate.en(e.html())),e.html(Reader.hyphenate.ru(e.html()))})}))},generateFontsCss:function(t){return`\n\t\t\t/** Calibri */\n\n\t\t\t@font-face {\n\t\t\t\tfont-family: 'Calibri';\n\t\t\t\tsrc: url(${Reader.Loader._res_data[t+"lib/fonts/calibriz.ttf"]});\n\t\t\t\tfont-style: italic;\n\t\t\t\tfont-weight : 700;\n\t\t\t}\n\n\t\t\t@font-face {\n\t\t\t\tfont-family: 'Calibri';\n\t\t\t\tsrc: url(${Reader.Loader._res_data[t+"lib/fonts/calibrib.ttf"]});\n\t\t\t\tfont-style: normal;\n\t\t\t\tfont-weight : 700;\n\t\t\t}\n\n\t\t\t@font-face {\n\t\t\t\tfont-family: 'Calibri';\n\t\t\t\tsrc: url(${Reader.Loader._res_data[t+"lib/fonts/calibrii.ttf"]});\n\t\t\t\tfont-style: italic;\n\t\t\t\tfont-weight : 400;\n\t\t\t}\n\n\t\t\t@font-face {\n\t\t\t\tfont-family: 'Calibri';\n\t\t\t\tsrc: url(${Reader.Loader._res_data[t+"lib/fonts/calibri.ttf"]});\n\t\t\t\tfont-style: normal;\n\t\t\t\tfont-weight : 400;\n\t\t\t}\n\n\t\t\t/** Cambria */\n\n\t\t\t@font-face {\n\t\t\t\tfont-family: 'Cambria';\n\t\t\t\tsrc: url(${Reader.Loader._res_data[t+"lib/fonts/cambriab.ttf"]});\n\t\t\t\tfont-style: normal;\n\t\t\t\tfont-weight : 700;\n\t\t\t}\n\n\t\t\t@font-face {\n\t\t\t\tfont-family: 'Cambria';\n\t\t\t\tsrc: url(${Reader.Loader._res_data[t+"lib/fonts/cambriaz.ttf"]});\n\t\t\t\tfont-style: italic;\n\t\t\t\tfont-weight : 700;\n\t\t\t}\n\n\t\t\t@font-face {\n\t\t\t\tfont-family: 'Cambria';\n\t\t\t\tsrc: url(${Reader.Loader._res_data[t+"lib/fonts/cambriai.ttf"]});\n\t\t\t\tfont-style: italic;\n\t\t\t\tfont-weight : 400;\n\t\t\t}\n\n\t\t\t@font-face {\n\t\t\t\tfont-family: 'Cambria';\n\t\t\t\tsrc: url(${Reader.Loader._res_data[t+"lib/fonts/cambria.ttf"]});\n\t\t\t\tfont-style: normal;\n\t\t\t\tfont-weight : 400;\n\t\t\t}\n\n\t\t\t/** Caecilia */\n\n\t\t\t@font-face {\n\t\t\t\tfont-family: Caecilia;\n\t\t\t\tsrc: url(${Reader.Loader._res_data[t+"lib/fonts/caecilia.ttf"]});\n\t\t\t\tfont-weight : normal;\n\t\t\t}\n\n\t\t\t@font-face {\n\t\t\t\tfont-family: Caecilia;\n\t\t\t\tsrc: url(${Reader.Loader._res_data[t+"lib/fonts/caeciliab.ttf"]});\n\t\t\t\tfont-weight : bold;\n\t\t\t}\n\n\t\t\t@font-face {\n\t\t\t\tfont-family: Caecilia;\n\t\t\t\tsrc: url(${Reader.Loader._res_data[t+"lib/fonts/caeciliai.ttf"]});\n\t\t\t\tfont-style : italic;\n\t\t\t}\n\n\t\t\t/** Palatino */\n\n\t\t\t@font-face {\n\t\t\t\tfont-family: 'Palatino';\n\t\t\t\tsrc: url(${Reader.Loader._res_data[t+"lib/fonts/palab.ttf"]});\n\t\t\t\tfont-style: normal;\n\t\t\t\tfont-weight : 700;\n\t\t\t}\n\n\t\t\t@font-face {\n\t\t\t\tfont-family: 'Palatino';\n\t\t\t\tsrc: url(${Reader.Loader._res_data[t+"lib/fonts/palabi.ttf"]});\n\t\t\t\tfont-style: italic;\n\t\t\t\tfont-weight : 700;\n\t\t\t}\n\n\t\t\t@font-face {\n\t\t\t\tfont-family: 'Palatino';\n\t\t\t\tsrc: url(${Reader.Loader._res_data[t+"lib/fonts/palai.ttf"]});\n\t\t\t\tfont-style: italic;\n\t\t\t\tfont-weight : 400;\n\t\t\t}\n\n\t\t\t@font-face {\n\t\t\t\tfont-family: 'Palatino';\n\t\t\t\tsrc: url(${Reader.Loader._res_data[t+"lib/fonts/pala.ttf"]});\n\t\t\t\tfont-style: normal;\n\t\t\t\tfont-weight : 400;\n\t\t\t}\n\n\t\t\t/** Consolas */\n\n\t\t\t@font-face {\n\t\t\t\tfont-family: 'Consolas';\n\t\t\t\tsrc: url(${Reader.Loader._res_data[t+"lib/fonts/consolab.ttf"]});\n\t\t\t\tfont-style: normal;\n\t\t\t\tfont-weight : 700;\n\t\t\t}\n\n\t\t\t@font-face {\n\t\t\t\tfont-family: 'Consolas';\n\t\t\t\tsrc: url(${Reader.Loader._res_data[t+"lib/fonts/consolaz.ttf"]});\n\t\t\t\tfont-style: italic;\n\t\t\t\tfont-weight : 700;\n\t\t\t}\n\n\t\t\t@font-face {\n\t\t\t\tfont-family: 'Consolas';\n\t\t\t\tsrc: url(${Reader.Loader._res_data[t+"lib/fonts/consolai.ttf"]});\n\t\t\t\tfont-style: italic;\n\t\t\t\tfont-weight : 400;\n\t\t\t}\n\n\t\t\t@font-face {\n\t\t\t\tfont-family: 'Consolas';\n\t\t\t\tsrc: url(${Reader.Loader._res_data[t+"lib/fonts/consola.ttf"]});\n\t\t\t\tfont-style: normal;\n\t\t\t\tfont-weight : 400;\n\t\t\t}\n\n\t\t\t/** IBM Plex Mono */\n\n\t\t\t@font-face {\n\t\t\t\tfont-family: 'IBM Plex Mono';\n\t\t\t\tsrc: url(${Reader.Loader._res_data[t+"lib/fonts/IBMPlexMono-Bold.otf"]});\n\t\t\t\tfont-style: normal;\n\t\t\t\tfont-weight : 700;\n\t\t\t}\n\n\t\t\t@font-face {\n\t\t\t\tfont-family: 'IBM Plex Mono';\n\t\t\t\tsrc: url(${Reader.Loader._res_data[t+"lib/fonts/IBMPlexMono-BoldItalic.otf"]});\n\t\t\t\tfont-style: italic;\n\t\t\t\tfont-weight : 700;\n\t\t\t}\n\n\t\t\t@font-face {\n\t\t\t\tfont-family: 'IBM Plex Mono';\n\t\t\t\tsrc: url(${Reader.Loader._res_data[t+"lib/fonts/IBMPlexMono-TextItalic.otf"]});\n\t\t\t\tfont-style: italic;\n\t\t\t\tfont-weight : 400;\n\t\t\t}\n\n\t\t\t@font-face {\n\t\t\t\tfont-family: 'IBM Plex Mono';\n\t\t\t\tsrc: url(${Reader.Loader._res_data[t+"lib/fonts/IBMPlexMono-Text.otf"]});\n\t\t\t\tfont-style: normal;\n\t\t\t\tfont-weight : 400;\n\t\t\t}\n\t\t\t`},flattenTocSubItems:function(t,e){let o=[];return 3!=e&&(t.subitems&&$.each(t.subitems,(function(t,a){a._nest=e,o.push(a),o=o.concat(Reader.flattenTocSubItems(a,e+1))})),o)},flattenToc:function(t){if(this._flattened_toc)return this._flattened_toc;{let e=[];return $.each(t.navigation.toc,(function(t,o){o._nest=0,e.push(o),e=e.concat(Reader.flattenTocSubItems(o,1))})),this._flattened_toc=e,e}},generateTocBar:function(t,e){$(".spacer").html(""),$.each(e,(function(e,o){try{const e=t.spine.get(o.href).cfiBase,a=t.locations._locations.find((function(t){return-1!=t.indexOf(e)}));if(a){const e=Math.round(100*t.locations.percentageFromCfi(a));$(".spacer").append($("<div class='toc-bar-entry'>").attr("data-nest-level",o._nest).css("left",e+"%").css("_width",3-o._nest+"px").attr("title",o.label))}}catch(t){console.warn(t)}})),$(".spacer").append($("<div class='toc-bar-entry current-position'>")),Reader.updateTocBarPosition(t,t.rendition.currentLocation())},updateTocBarPosition:function(t,e){const o=Math.round(e.start.location/t.locations.length()*100);$(".toc-bar-entry.current-position").css("left",o+"%")},applyStyles:function(t){Promise.all([localforage.getItem("epube.fontSize"),localforage.getItem("epube.fontFamily"),localforage.getItem("epube.lineHeight"),localforage.getItem("epube.theme")]).then((function(e){const o=e[0]?e[0]+"px":"16px",a=e[1]?e[1]:"Arial",n=e[2]?e[2]+"%":"140%";console.log("style",a,o,n),console.log("applying default theme..."),window.book.rendition.themes.default({html:{"font-size":o,"font-family":"'"+a+"'","line-height":n,"text-align":"justify","text-indent":"1em"}}),t||(console.log("applying rendition themes..."),$.each(window.book.rendition.getContents(),(function(t,e){e.css("font-size",o),e.css("font-family","'"+a+"'"),e.css("line-height",n),e.css("text-align","justify")}))),Reader.applyTheme()}))},applyTheme:async function(){let t=await localforage.getItem("epube.theme")||"default";console.log("called for theme",t),"default"==t&&"undefined"!=typeof EpubeApp&&EpubeApp.isNightMode()&&(t="night"),console.log("setting main UI theme",t),$("body").attr("class","undefined"!=typeof EpubeApp?"is-epube-app":"").addClass("epube-reader theme-"+t).attr("data-is-loading","false"),"undefined"!=typeof EpubeApp&&window.setTimeout((function(){const t=window.getComputedStyle(document.querySelector("body"),null).getPropertyValue("background-color").match(/rgb\((\d{1,}), (\d{1,}), (\d{1,})\)/);t&&(console.log("sending bgcolor",t),EpubeApp.setStatusBarColor(parseInt(t[1]),parseInt(t[2]),parseInt(t[3])))}),250),window.book&&$.each(window.book.rendition.getContents(),(function(e,o){console.log("applying rendition theme",t,"to",o,o.document),$(o.document).find("body").attr("class","undefined"!=typeof EpubeApp?"is-epube-app":"").addClass("theme-"+t)}))},hotkeyHandler:function(t){try{if($(".modal").is(":visible"))return;39!=t.which&&32!=t.which&&34!=t.which||(t.preventDefault(),Reader.Page.next()),37!=t.which&&33!=t.which||(t.preventDefault(),Reader.Page.prev()),27==t.which&&(t.preventDefault(),Reader.showUI(!0))}catch(t){console.warn(t)}},resizeSideColumns:function(){let t=$("#reader").position().left;const e=$("#reader iframe")[0];e&&e.contentWindow.$&&(t+=parseInt(e.contentWindow.$("body").css("padding-left"))),$("#left, #right").width(t)},markAsRead:async function(){if(confirm("Mark book as read?")){const t=100,e=window.book.locations.cfiFromPercentage(1),o=(new Date).getTime();if(App.isOnline()){const a=await $.post("backend.php",{op:"storelastread",page:t,cfi:e,id:$.urlParam("id"),timestamp:o});$(".lastread_input").val(a.page+"%")}await localforage.setItem(Reader.cacheId("lastread"),{cfi:e,page:t,total:t,timestamp:o})}},close:async function(){const t=window.book.rendition.currentLocation().start.cfi,e=parseInt(100*window.book.locations.percentageFromCfi(t)),o=(new Date).getTime();await localforage.setItem(Reader.cacheId("lastread"),{cfi:t,page:e,total:100,timestamp:o}),App.isOnline()?$.post("backend.php",{op:"storelastread",id:$.urlParam("id"),page:e,cfi:t,timestamp:o},(function(){window.location=$.urlParam("rt")?"index.php?mode="+$.urlParam("rt"):"index.php"})).fail((function(){window.location="index.php"})):window.location="index.php"},cacheId:function(t){return"epube-book."+$.urlParam("b")+(t?"."+t:"")},toggleFullscreen:function(){if("undefined"!=typeof EpubeApp);else{const t=document.documentElement,e=document.webkitIsFullScreen||document.mozFullScreen||!1;t.requestFullScreen=t.requestFullScreen||t.webkitRequestFullScreen||t.mozRequestFullScreen||function(){return!1},document.cancelFullScreen=document.cancelFullScreen||document.webkitCancelFullScreen||document.mozCancelFullScreen||function(){return!1},e?document.cancelFullScreen():t.requestFullScreen()}},showUI:function(t){t?$(".header,.footer").fadeIn():$(".header,.footer").fadeOut()},toggleUI:function(){$(".header").is(":visible")?$(".header,.footer").fadeOut():$(".header,.footer").fadeIn()},lookupWord:async function(t,e){t=t.replace(/­/g,""),$(".dict_result").html("Loading, please wait..."),$("#dict-modal").modal("show");try{const o=await $.post("backend.php",{op:"define",word:t});o&&($(".dict_result").html(o.result.join("<br/>")),$(".dict_query").val(t),e&&e())}catch(t){console.error(t),$(".dict_result").html(`Network error while looking up word: ${t.responseText}.`)}},search:function(){const t=$(".search_input").val(),e=$(".search_results");e.html(""),t&&Promise.all(window.book.spine.spineItems.map(e=>e.load(window.book.load.bind(window.book)).then(e.find.bind(e,t)).finally(e.unload.bind(e)))).then(t=>Promise.resolve([].concat.apply([],t))).then((function(t){$.each(t,(function(t,o){const a=$("<a>").attr("href","#").html("<b class='pull-right'>"+window.book.locations.locationFromCfi(o.cfi)+"</b>"+o.excerpt).attr("data-cfi",o.cfi).attr("data-id",o.id).click((function(){window.book.rendition.display(a.attr("data-cfi"))}));e.append($("<li>").append(a))}))}))},Loader:{_res_data:[],init:async function(){const t=[];let e=!1;const o=await caches.open("epube-v3");(await o.keys()).forEach(o=>{if(!o.url.match("backend.php")){console.log("[loader] loading resource",o.url);const a=fetch(o.url).then(async t=>{if(t.ok){const e=new URL(t.url);if(e.searchParams.delete("ts"),t.url.match("\\.ttf|\\.otf")){const o=await t.blob();console.log("[loader] storing blob",e.href),Reader.Loader._res_data[e.toString()]=URL.createObjectURL(o)}else{const o=await t.text();console.log("[loader] storing text",e.href),Reader.Loader._res_data[e.toString()]=o}}else console.warn("[loader] failed for resource",o.url,t),$(".loading-message").html(`Unable to load resource.<br/><small>${o.url}</small>`),e=!0});t.push(a)}}),await Promise.allSettled(t),console.log("[loader] resource load complete, failed: ",e),e?Reader.applyTheme():Reader.initSecondStage()}},Page:{_moved_next:0,_prevent_lastread_timeout:!1,_prevent_lastread:!1,next:function(){window.book.rendition.next(),Reader.Page._moved_next+=1,"undefined"!=typeof EpubeApp?EpubeApp.showActionBar(!1):localforage.getItem("epube.keep-ui-visible").then((function(t){t||Reader.showUI(!1)}))},prev:function(){window.book.rendition.prev(),"undefined"!=typeof EpubeApp?EpubeApp.showActionBar(!1):localforage.getItem("epube.keep-ui-visible").then((function(t){t||Reader.showUI(!1)}))},openPrevious:async function(t){const e=$(t).attr("data-location-cfi");e&&await window.book.rendition.display(e),$(t).fadeOut()},blockLastReadUpdate:function(){console.log("blocking last read updates..."),Reader.Page._prevent_lastread_timeout&&window.clearTimeout(Reader.Page._prevent_lastread_timeout),Reader.Page._prevent_lastread_timeout=window.setTimeout(()=>{Reader.Page._prevent_lastread=!1,Reader.Page._prevent_lastread_timeout=!1,console.log("unblocked last read updates")},1e3),Reader.Page._prevent_lastread=!0},onRelocated:async function(t,e){const o=t.rendition;if(0==t.locations.length())return;await localforage.getItem("epube.enable-column-hacks")&&Reader.Page._moved_next>=20&&(console.log("forcing re-render because of column hacks"),o.onResized($("#reader").width()),Reader.Page._moved_next=0);const a=e.start.cfi,n=parseInt(100*t.locations.percentageFromCfi(a));$("#cur_page").text(Math.floor(e.start.location/10)),$("#total_pages").text(Math.floor(t.locations.length()/10)),$("#page_pct").text(parseInt(100*t.locations.percentageFromCfi(a))+"%"),Reader.updateTocBarPosition(t,e);const i=e.start.displayed;if(i&&($("#chapter_cur_page").text(i.page),$("#chapter_total_pages").text(i.total),i.total>0&&$("#chapter_pct").text(parseInt(i.page/i.total*100)+"%")),Reader.startup_finished&&Reader.last_stored_cfi!=a&&!Reader.Page._prevent_lastread){const t=(new Date).getTime();console.log("storing lastread",n,a,t),await localforage.setItem(Reader.cacheId("lastread"),{cfi:a,page:n,total:100,timestamp:t}),App.isOnline()&&(console.log("updating remote lastread",a),Reader.last_stored_cfi=a,$.post("backend.php",{op:"storelastread",id:$.urlParam("id"),page:n,cfi:a,timestamp:t}))}},clearLastRead:async function(){if(confirm("Clear stored last read location?")){const t=window.book.locations.length(),e=(new Date).getTime();if(App.isOnline()){const t=await $.post("backend.php",{op:"storelastread",page:-1,cfi:"",id:$.urlParam("id"),timestamp:e});$(".lastread_input").val(t.page+"%")}await localforage.setItem(Reader.cacheId("lastread"),{cfi:"",page:0,total:t,timestamp:e}),await window.book.rendition.display(window.book.locations.cfiFromPercentage(0))}},openLastRead:async function(){$(".loading-message").html("Opening last read page…");const t=window.book.rendition;if(!t)return void console.error("no rendition to work on");let e=!1;const o=await localforage.getItem(Reader.cacheId("lastread"))||{};if(console.log("got local lastread",o),o&&o.cfi){console.log("using local lastread cfi",o.cfi);try{await Reader.Page.moveToCfiVerify(t,o.cfi),e=!0}catch(t){console.warn(t)}}if(App.isOnline())try{const a=await $.post("backend.php",{op:"getlastread",id:$.urlParam("id")});console.log("got remote lastread",a),a&&a.cfi&&o.cfi!=a.cfi&&a.timestamp>=(o.timestamp||0)&&(console.log(`using remote lastread cfi ${a.cfi} (timestamp is newer or local timestamp is missing)`),await localforage.setItem(Reader.cacheId("lastread"),{cfi:a.cfi,page:a.page,total:a.total,timestamp:a.timestamp}),await Reader.Page.moveToCfiVerify(t,a.cfi),e=!0)}catch(t){console.log("unable to get remote lastread, continuing..."),console.warn(t)}e||t.display(),$(".loading").hide()},moveToCfiVerify:async function(t,e,o=3){for(let a=1;a<o;a++){Reader.Page.blockLastReadUpdate(),console.log(`trying to open ${e}: attempt ${a} of ${o}...`),await t.display(e);const n=t.currentLocation().start.cfi;if(console.log(`opened cfi ${n} expected ${e}`),n==e)return}}},Settings:{onThemeChanged:async function(t){const e=$(t).val();await localforage.setItem("epube.theme",e),Reader.applyTheme()},onLineHeightChanged:async function(t){const e=$(t).val();await localforage.setItem("epube.lineHeight",e),Reader.applyStyles()},onTextSizeChanged:async function(t){const e=$(t).val();await localforage.setItem("epube.fontSize",e),Reader.applyStyles()},onFontChanged:async function(t){const e=$(t).val();await localforage.setItem("epube.fontFamily",e),Reader.applyStyles()}}};function __get_reader(){return Reader}function __get_app(){return App} \ No newline at end of file
+"use strict";$.urlParam=function(t){try{const e=new RegExp("[?&]"+t+"=([^&#]*)").exec(window.location.href);return decodeURIComponent(e[1].replace(/\+/g," "))||0}catch(t){return 0}};const Cookie={set:function(t,e,o){const n=new Date;n.setTime(n.getTime()+1e3*o);const a="expires="+n.toUTCString();document.cookie=t+"="+encodeURIComponent(e)+"; "+a},get:function(t){t+="=";const e=document.cookie.split(";");for(let o=0;o<e.length;o++){let n=e[o];for(;" "==n.charAt(0);)n=n.substring(1);if(0==n.indexOf(t))return decodeURIComponent(n.substring(t.length,n.length))}return""},delete:function(t){document.cookie=t+"=; expires=Thu, 01-Jan-1970 00:00:01 GMT"}},App={_dl_progress_timeout:!1,index_mode:"",cached_urls:[],version:"UNKNOWN",csrf_token:"",init:function(){let t=0;this.csrf_token=Cookie.get("epube_csrf_token"),console.log("setting prefilter for token",this.csrf_token),$.ajaxPrefilter((function(t,e,o){if("post"!==e.type||"post"!==t.type)return;const n=typeof e.data;"object"==n?t.data=$.param($.extend(e.data,{csrf_token:App.csrf_token})):"string"==n&&(t.data=e.data+"&csrf_token="+encodeURIComponent(App.srf_token)),console.log(">>>",t)})),"undefined"!=typeof EpubeApp&&($(".navbar").hide(),$(".epube-app-filler").show(),$(".separate-search").show(),"favorites"==$.urlParam("mode")?EpubeApp.setPage("PAGE_FAVORITES"):EpubeApp.setPage("PAGE_LIBRARY")),App.initNightMode(),"serviceWorker"in navigator?(navigator.serviceWorker.addEventListener("message",(function(e){"refresh-started"==e.data&&(console.log("cache refresh started"),t=0,$(".dl-progress").fadeIn().text("Loading, please wait...")),e.data&&0==e.data.indexOf("refreshed:")&&(++t,$(".dl-progress").fadeIn().text("Updated "+t+" files...")),"refresh-finished"==e.data&&(localforage.setItem("epube.cache-version",App.version),window.location.reload())})),App.showCovers(),App.Offline.markBooks(),App.refreshCache()):$(".container-main").addClass("alert alert-danger").html("Service worker support missing in browser (are you using plain HTTP?).")},logout:function(){$.post("backend.php",{op:"logout"}).then(()=>{window.location.reload()})},showSummary:function(t){const e=t.getAttribute("data-book-id");return $.post("backend.php",{op:"getinfo",id:e},(function(t){const e=t.comment?t.comment:"No description available";$("#summary-modal .modal-title").html(t.title),$("#summary-modal .book-summary").html(e),$("#summary-modal").modal()})),!1},showCovers:function(){$("img[data-book-id]").each((t,e)=>{if((e=$(e)).attr("data-cover-link")){const t=$("<img>").on("load",(function(){e.css("background-image","url("+e.attr("data-cover-link")+")").fadeIn(),t.attr("src",null)})).attr("src",e.attr("data-cover-link"))}})},toggleFavorite:function(t){const e=t.getAttribute("data-book-id");return("0"==t.getAttribute("data-is-fav")||confirm("Remove favorite?"))&&$.post("backend.php",{op:"togglefav",id:e},(function(o){if(o){let n="[Error]";0==o.status?n="Add to favorites":1==o.status&&(n="Remove from favorites"),$(t).html(n).attr("data-is-fav",o.status),"favorites"==App.index_mode&&0==o.status&&$("#cell-"+e).remove()}})),!1},refreshCache:function(t){"serviceWorker"in navigator?localforage.getItem("epube.cache-version").then((function(e){console.log("local version",e,"remote version",App.version),(t||e!=App.version)&&(console.log("asking worker to refresh cache"),navigator.serviceWorker.controller?navigator.serviceWorker.controller.postMessage({msg:"refresh-cache",urls:App.cached_urls}):localforage.getItem("epube.initial-load-done").then((function(t){console.log("initial load done",t),t?$(".dl-progress").show().addClass("alert-danger").html("Could not communicate with service worker. Try reloading the page."):localforage.setItem("epube.initial-load-done",!0).then((function(){$(".dl-progress").show().addClass("alert-info").html("Page will reload to activate service worker..."),window.setTimeout((function(){window.location.reload()}),3e3)}))})))})):$(".dl-progress").show().addClass("alert-danger").html("Could not communicate with service worker. Try reloading the page.")},isOnline:function(){return"undefined"!=typeof EpubeApp&&void 0!==EpubeApp.isOnline?EpubeApp.isOnline():navigator.onLine},appCheckOffline:function(){EpubeApp.setOffline(!App.isOnline)},initNightMode:function(){if("undefined"==typeof EpubeApp){if(window.matchMedia){const t=window.matchMedia("(prefers-color-scheme: dark)");t.addEventListener("change",()=>{App.applyNightMode(t.matches)}),App.applyNightMode(t.matches)}}else App.applyNightMode(EpubeApp.isNightMode())},applyNightMode:function(t){console.log("night mode changed to",t),$("#theme_css").attr("href","lib/bootstrap/v3/css/"+(t?"theme-dark.min.css":"bootstrap-theme.min.css"))},Offline:{init:function(){"undefined"!=typeof EpubeApp&&($(".navbar").hide(),$(".epube-app-filler").show(),EpubeApp.setPage("PAGE_OFFLINE")),App.initNightMode();const t=$.urlParam("query");t&&$(".search_query").val(t),App.Offline.populateList()},get:function(t,e){console.log("offline cache: "+t),$.post("backend.php",{op:"getinfo",id:t},(function(o){if(o){const n="epube-book."+t;localforage.setItem(n,o).then((function(o){console.log(n+" got data");const a=[];a.push(fetch("backend.php?op=download&id="+o.epub_id,{credentials:"same-origin"}).then((function(t){200==t.status&&(console.log(n+" got book"),e(),localforage.setItem(n+".book",t.blob()))}))),a.push(fetch("backend.php?op=getpagination&id="+o.epub_id,{credentials:"same-origin"}).then((function(t){200==t.status&&(console.log(n+" got pagination"),t.text().then((function(t){localforage.setItem(n+".locations",JSON.parse(t))})))}))),a.push(fetch("backend.php?op=getlastread&id="+o.epub_id,{credentials:"same-origin"}).then((function(t){200==t.status&&(console.log(n+" got lastread"),t.text().then((function(t){localforage.setItem(n+".lastread",JSON.parse(t))})))}))),o.has_cover&&a.push(fetch("backend.php?op=cover&id="+t,{credentials:"same-origin"}).then((function(t){200==t.status&&(console.log(n+" got cover"),localforage.setItem(n+".cover",t.blob()))}))),Promise.all(a).then((function(){$(".dl-progress").show().html("Finished downloading <b>"+o.title+"</b>"),window.clearTimeout(App._dl_progress_timeout),App._dl_progress_timeout=window.setTimeout((function(){$(".dl-progress").fadeOut()}),5e3)}))}))}}))},getAll:function(){confirm("Download all books on this page?")&&$(".row > div").each((function(t,e){const o=$(e).attr("id").replace("cell-",""),n=$(e).find(".offline_dropitem")[0];if(o){const t="epube-book."+o;localforage.getItem(t).then((function(t){t||App.Offline.get(o,(function(){App.Offline.mark(n)}))}))}}))},markBooks:function(){const t=$(".offline_dropitem");$.each(t,(function(t,e){App.Offline.mark(e)}))},mark:function(t){const e=t.getAttribute("data-book-id"),o="epube-book."+e;localforage.getItem(o).then((function(o){o?(t.onclick=function(){return App.Offline.remove(e,(function(){App.Offline.mark(t)})),!1},t.innerHTML="Remove offline data"):(t.onclick=function(){return App.Offline.get(e,(function(){App.Offline.mark(t)})),!1},t.innerHTML="Make available offline")}))},removeFromList:function(t){const e=t.getAttribute("data-book-id");return App.Offline.remove(e,(function(){$("#cell-"+e).remove()}))},remove:function(t,e){if(confirm("Remove download?")){const o="epube-book."+t,n=[];console.log("offline remove: "+t),localforage.iterate((function(t,e){e.match(o)&&n.push(localforage.removeItem(e))})),Promise.all(n).then((function(){window.setTimeout((function(){e()}),500)}))}},search:function(){const t=$(".search_query").val();return localforage.setItem("epube.search-query",t).then((function(){App.Offline.populateList()})),!1},removeAll:function(){if(confirm("Remove all downloaded books?")){const t=[];localforage.iterate((function(e,o){o.match("epube-book")&&t.push(localforage.removeItem(o))})),Promise.all(t).then((function(){window.setTimeout((function(){App.Offline.populateList()}),500)}))}},showSummary:function(t){const e=t.getAttribute("data-book-id");return localforage.getItem("epube-book."+e).then((function(t){const e=t.comment?t.comment:"No description available";$("#summary-modal .modal-title").html(t.title),$("#summary-modal .book-summary").html(e),$("#summary-modal").modal()})),!1},populateList:function(){let t=$.urlParam("query");t&&(t=t.toLowerCase());const e=$("#books_container");e.html(""),localforage.iterate((function(o,n){n.match(/epube-book\.\d{1,}$/)&&Promise.all([localforage.getItem(n),localforage.getItem(n+".cover"),localforage.getItem(n+".lastread"),localforage.getItem(n+".book")]).then((function(o){if(o[0]&&o[3]){const n=o[0];if(t){if(!(n.series_name&&n.series_name.toLowerCase().match(t)||n.title&&n.title.toLowerCase().match(t)||n.author_sort&&n.author_sort.toLowerCase().match(t)))return}let a=!1;o&&o[1]&&(a=URL.createObjectURL(o[1]));let i=!1,r=!1;const l=o[2];l&&(i=l.page>0,r=l.total>0&&l.total-l.page<5);const s=r?"read":"",c=i?"in_progress":"",d=n.series_name?`<div><a class="series_link" href="#">${n.series_name+" ["+n.series_index+"]"}</a></div>`:"",f=$(`<div class="col-xxs-6 col-xs-4 col-sm-3 col-md-2" id="cell-${n.id}">\n\t\t\t\t\t\t\t<a class="thumbnail ${s}" href="read.html?id=${n.epub_id}&b=${n.id}">\n\t\t\t\t\t\t\t\t<img style="display : none">\n\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t\t<div class="caption">\n\t\t\t\t\t\t\t\t<div><a class="${c}" href="read.html?id=${n.epub_id}&b=${n.id}">${n.title}</a></div>\n\t\t\t\t\t\t\t\t<div><a class="author_link" href="#">${n.author_sort}</a></div>\n\t\t\t\t\t\t\t\t${d}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<div class="dropdown" style="white-space : nowrap">\n\t\t\t\t\t\t\t\t<a href="#" data-toggle="dropdown" role="button">More...<span class="caret"></span></a>\n\t\t\t\t\t\t\t\t<ul class="dropdown-menu">\n\t\t\t\t\t\t\t\t\t<li><a href="#" data-book-id="${n.id}" onclick="return App.Offline.showSummary(this)">Summary</a></li>\n\t\t\t\t\t\t\t\t\t<li><a href="#" data-book-id="${n.id}" onclick="App.Offline.removeFromList(this)">Remove offline data</a></li>\n\t\t\t\t\t\t\t\t</ul>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>`);a?f.find("img").css("background-image","url("+a+")").fadeIn():f.fadeIn(),f.find(".series_link").attr("title",n.series_name+" ["+n.series_index+"]").attr("href","offline.html?query="+encodeURIComponent(n.series_name)),f.find(".author_link").attr("title",n.author_sort).attr("href","offline.html?query="+encodeURIComponent(n.author_sort)),e.append(f)}}))}))}}},DEFAULT_FONT_SIZE=16,DEFAULT_FONT_FAMILY="Arial",DEFAULT_LINE_HEIGHT=140,MIN_LENGTH_TO_JUSTIFY=32,LOCATION_DIVISOR=10,PAGE_RESET_PROGRESS=-1,CACHE_PREFIX="epube",CACHE_NAME="epube-v3";Promise.allSettled=Promise.allSettled||(t=>Promise.all(t.map(t=>t.then(t=>({status:"fulfilled",value:t})).catch(t=>({status:"rejected",reason:t})))));const Reader={csrf_token:"",last_stored_cfi:"",startup_finished:!1,hyphenate:{},init:function(){this.csrf_token=Cookie.get("epube_csrf_token"),console.log("setting prefilter for token",this.csrf_token),$.ajaxPrefilter((function(t,e){if("post"!==e.type||"post"!==t.type)return;const o=typeof e.data;"object"==o?t.data=$.param($.extend(e.data,{csrf_token:Reader.csrf_token})):"string"==o&&(t.data=e.data+"&csrf_token="+encodeURIComponent(Reader.srf_token)),console.log(">>>",t)})),$(document).on("keyup",(function(t){Reader.hotkeyHandler(t)})),$("#left").on("mouseup",(function(){Reader.Page.prev()})),$("#right").on("mouseup",(function(){Reader.Page.next()})),Reader.Loader.init()},onOfflineModeChanged:function(t){if(console.log("onOfflineModeChanged",t),!t&&window.book){const t=window.book;console.log("we're online, storing lastread");const e=t.rendition.currentLocation().start.cfi,o=parseInt(100*t.locations.percentageFromCfi(e));$.post("backend.php",{op:"storelastread",id:$.urlParam("id"),page:o,cfi:e,timestamp:(new Date).getTime()},(function(){})).fail((function(t){t&&401==t.status&&(window.location="index.php")}))}},initSecondStage:async function(){"undefined"!=typeof EpubeApp?EpubeApp.setPage("PAGE_READER"):($(window).on("online",(function(){Reader.onOfflineModeChanged(!1)})),$(window).on("offline",(function(){Reader.onOfflineModeChanged(!0)}))),Reader.applyTheme();if(!await localforage.getItem(Reader.cacheId())){const t=$.urlParam("b");console.log("requesting bookinfo for book",t);try{const e=await $.post("backend.php",{op:"getinfo",id:t});if(e.has_cover){const e=await fetch("backend.php?op=cover&id="+t);e.ok&&await localforage.setItem(Reader.cacheId("cover"),e.blob())}await localforage.setItem(Reader.cacheId(),e),console.log("bookinfo saved")}catch(t){return void $(".loading-message").html(`Unable to load book info.<br/><small>${t.responseText}</small>`)}}console.log("trying to load book...");let t=await localforage.getItem(Reader.cacheId("book"));if(!t){console.log("local data not found, loading from network..."),$(".loading-message").html("Downloading book…");const e=await fetch("backend.php?op=download&id="+$.urlParam("id"));if(!e.ok)return void $(".loading-message").html("Unable to download book: "+e.status);if(t=await e.blob(),!t)return void $(".loading-message").html("Unable to get book blob data.");await localforage.setItem(Reader.cacheId("book"),t),console.log("saved local data for book")}const e=new FileReader;e.onload=function(){try{Reader.openBookData(this.result)}catch(t){console.error(t),$(".loading-message").html("Unable to load book blob: "+t)}},e.onerror=t=>{console.log("filereader error",t),$(".loading-message").html("Unable to open book.<br/><small>"+t+"</small>")},e.readAsArrayBuffer(t)},openBookData:async function(t){const e=ePub();window.book=e;try{await e.open(t)}catch(t){return console.error(t),void $(".loading-message").html("Unable to open book.<br/><small>"+t.message+"</small>")}await e.ready,console.log("book is ready"),await Reader.showBookInfo(e),await Reader.loadLocations(e);const o=e.renderTo("reader",{width:"100%",height:"100%",allowScriptedContent:!0,minSpreadWidth:961});$(".location").click((async function(){const t=Math.floor(o.currentLocation().start.location/10),n=Math.floor(e.locations.length()/10),a=prompt("Jump to location [1-"+n+"]",t);a&&await o.display(e.locations._locations[10*a])}));await localforage.getItem("epube.enable-hyphens")&&(Reader.hyphenate.en=createHyphenator(hyphenationPatternsEnUs,{html:!0}),Reader.hyphenate.ru=createHyphenator(hyphenationPatternsRu,{html:!0})),Reader.applyStyles(!0),console.log("book displayed"),Reader.initRenditionHooks(e,o),Reader.initModals(),Reader.initToc(e),Reader.initStyleHooks(e),await Reader.Page.openLastRead(),console.log("startup finished"),Reader.startup_finished=!0},showBookInfo:async function(t){const e=await localforage.getItem(Reader.cacheId());let o,n;if(e)o=e.title,n=e.author_sort;else{const e=t.package.metadata;o=e.title,n=e.creator}document.title=o+" – "+n+" – The Epube",$(".title").text(o).attr("title",o+" – "+n),"undefined"!=typeof EpubeApp&&(EpubeApp.setTitle(o),EpubeApp.showActionBar(!1))},loadLocations:async function(t){let e=await localforage.getItem(Reader.cacheId("locations"));if(e&&"string"==typeof e[0]){console.log("loading local locations...");try{return void await t.locations.load(e)}catch(t){console.warn(t)}}if(App.isOnline()){console.log("downloading locations..."),$(".loading-message").html("Downloading locations…");const o=await fetch("backend.php?op=getpagination&id="+$.urlParam("id"));if(o.ok&&(console.log("got locations from server"),e=await o.json(),e&&"string"==typeof e[0])){console.log("saving locations locally..."),await localforage.setItem(Reader.cacheId("locations"),e);try{return void t.locations.load(e)}catch(t){console.warn(t)}}}$(".loading-message").html("Preparing locations…"),e=await t.locations.generate(100),$.post("backend.php",{op:"storepagination",id:$.urlParam("id"),payload:JSON.stringify(e),total:100}),await localforage.setItem(Reader.cacheId("locations"),e)},initRenditionHooks:function(t,e){e.hooks.content.register(async t=>{t.on("linkClicked",t=>{console.log("linkClicked",t),Reader.Page.blockLastReadUpdate(),-1==t.indexOf("://")&&($(".prev_location_btn").attr("data-location-cfi",e.currentLocation().start.cfi).show(),window.setTimeout((function(){Reader.showUI(!0)}),50))});const o=window.location.href.match(/^.*\//)[0];"undefined"!=typeof EpubeApp?$(t.document.head).append($('<link type="text/css" rel="stylesheet" media="screen" href="/assets/android.css" />')):$(t.document.head).append($("<style type='text/css'>").text(Reader.generateFontsCss(o)));const n=["dist/app-libs.min.js","dist/reader_iframe.min.js"];for(let e=0;e<n.length;e++){const a=t.document.createElement("script");a.type="text/javascript",a.text=Reader.Loader._res_data[o+n[e]],t.document.head.appendChild(a)}$(t.document.head).append($("<style type='text/css'>").text(Reader.Loader._res_data[o+"dist/reader_iframe.min.css"]));const a=await localforage.getItem("epube.theme")||"default";$(t.document).find("body").attr("class","undefined"!=typeof EpubeApp?"is-epube-app":"").addClass("theme-"+a)}),e.on("keyup",t=>{Reader.hotkeyHandler(t)}),e.on("rendered",(function(){$(".chapter").html($("<span>").addClass("glyphicon glyphicon-th-list")),setTimeout(()=>{Reader.Page._moved_next=0},150),Reader.applyTheme(),Reader.resizeSideColumns();try{const o=e.currentLocation();if(o.start){const e=t.canonical(o.start.href);let n=!1;$.each(Reader.flattenToc(t),(function(o,a){t.spine.get(a.href).canonical!=e||(n=a)})),n&&n.label&&$(".chapter").append("&nbsp;"+n.label.trim()+" | "),Reader.generateTocBar(t,Reader.flattenToc(t))}}catch(t){console.warn(t)}})),e.on("relocated",e=>Reader.Page.onRelocated(t,e))},initModals:function(){$("#settings-modal").on("shown.bs.modal",(async function(){const t=await localforage.getItem(Reader.cacheId("lastread"));t&&t.cfi&&$(".lastread_input").val(t.page+"%").attr("title","[local] "+t.cfi),navigator.onLine&&$.post("backend.php",{op:"getlastread",id:$.urlParam("id")},t=>{$(".lastread_input").val(t.page+"%").attr("title","[remote] "+t.cfi)}),$(".enable_hyphens_checkbox").attr("checked",await localforage.getItem("epube.enable-hyphens")).off("click").on("click",(function(t){localforage.setItem("epube.enable-hyphens",t.target.checked),confirm("Toggling hyphens requires page reload. Reload now?")&&window.location.reload()})),"undefined"!=typeof EpubeApp?$(".keep_ui_checkbox").parent().parent().hide():$(".keep_ui_checkbox").attr("checked",await localforage.getItem("epube.keep-ui-visible")).off("click").on("click",(function(t){localforage.setItem("epube.keep-ui-visible",t.target.checked)}));const e=await localforage.getItem("epube.enable-column-hacks");$(".enable_column_hacks_checkbox").attr("checked",e).off("click").on("click",(function(t){localforage.setItem("epube.enable-column-hacks",t.target.checked)}));const o=await localforage.getItem("epube.cache-timestamp"),n=await localforage.getItem("epube.cache-version");$(".last-mod-timestamp").html(`${n}\n\t\t\t\t&mdash; ${parseInt(o)?new Date(1e3*o).toLocaleString("en-GB"):"Unknown"}\n\t\t\t\t(${App.isOnline()?"<span class='text-success'>Online</span>":"<span class='text-danger'>Offline</span>"})\n\t\t\t\t`),$(".font_family").val(await localforage.getItem("epube.fontFamily")||"Arial"),$(".theme_name").val(await localforage.getItem("epube.theme")||"default");const a=$(".font_size").html("");for(let t=10;t<=32;t++){const e=$("<option>").val(t).html(t+" px");a.append(e)}a.val(await localforage.getItem("epube.fontSize")||16);const i=$(".line_height").html("");for(let t=100;t<=220;t+=10){const e=$("<option>").val(t).html(t+"%");i.append(e)}i.val(await localforage.getItem("epube.lineHeight")||140)})),$("#dict-modal").on("shown.bs.modal",(function(){$(".dict_result").scrollTop(0)})),$(".dict_search_btn").on("click",(function(){$("#dict-modal").modal("hide"),window.open("https://duckduckgo.com/?q="+$(".dict_query").val())})),$(".wiki_search_btn").on("click",(function(){$(".dict_result").html("Loading, please wait..."),$.post("backend.php",{op:"wikisearch",query:$(".dict_query").val()}).then(t=>{try{console.log("wikisearch resp",t);let e="";$.each(t.query.pages,(t,o)=>{e+=o.extract}),$(".dict_result").html(e&&"undefined"!=e?e:"No definition found for "+$(".dict_query").val()+".")}catch(t){console.error(t),$(".dict_result").text("Error while processing data: "+t)}}).fail(t=>{console.error(t),$(".dict_result").text("Error while retrieving data.")})}))},initToc:function(t){function e(e){try{const o=t.spine.get(e).cfiBase,n=t.locations._locations.find((function(t){return-1!=t.indexOf(o)}));return parseInt(window.book.locations.locationFromCfi(n)/10)}catch(t){console.warn(t)}return""}$("#toc-modal").on("shown.bs.modal",(function(){const o=t.navigation.toc,n=$(".toc_list");n.html(""),$.each(o,(function(o,a){try{const o=$("<a>").attr("href","#").html("<b class='pull-right'>"+e(a.href)+"</b>"+a.label).attr("data-href",a.href).click((function(){t.rendition.display(o.attr("data-href"))}));n.append($("<li>").append(o)),function o(n,a,i){if(3==i)return!1;if(n.subitems){const r=$("<ul class='toc_sublist list-unstyled'>");$.each(n.subitems,(function(n,a){const l=$("<a>").attr("href","#").html("<b class='pull-right'>"+e(a.href)+"</b>"+a.label).attr("data-href",a.href).click((function(){t.rendition.display(l.attr("data-href"))}));r.append($("<li>").append(l)),o(a,r,i+1)})),a.append(r)}}(a,n,0)}catch(t){console.warn(t)}})),n.children().length<=1&&(n.html(""),$.each(t.spine.items,(function(e,o){const a=$("<a>").attr("href","#").attr("title",o.url).html("Section "+(e+1)).attr("data-href",o.href).click((function(){t.rendition.display(a.attr("data-href"))}));n.append($("<li>").append(a))})))}))},initStyleHooks:function(t){t.spine.hooks.content.register((function(t){$(t).find("p").filter((t,e)=>$(e).text().length>=32?e:null).css("text-align","justify"),$(t).find("html").attr("class",""),$(t).find("pre").css("white-space","pre-wrap"),$(t).find("a, p, span, em, i, strong, b, body, header, section, div, big, small, table, tr, td, ul, ol, li").attr("class","").css("font-family","inherit").css("font-size","inherit").css("line-height","inherit").css("color","").css("border","none ! important").css("background","").css("background-color","").attr("width","").attr("height",""),$(t).find("h1, h2, h3, h4, h5").attr("class","").css("font-family","inherit").css("color","").css("border","none ! important").css("background","").css("background-color",""),void 0!==Reader.hyphenate.en&&$(t).find("p, div").each((t,e)=>{(e=$(e)).html(Reader.hyphenate.en(e.html())),e.html(Reader.hyphenate.ru(e.html()))})}))},generateFontsCss:function(t){return`\n\t\t\t/** Calibri */\n\n\t\t\t@font-face {\n\t\t\t\tfont-family: 'Calibri';\n\t\t\t\tsrc: url(${Reader.Loader._res_data[t+"lib/fonts/calibriz.ttf"]});\n\t\t\t\tfont-style: italic;\n\t\t\t\tfont-weight : 700;\n\t\t\t}\n\n\t\t\t@font-face {\n\t\t\t\tfont-family: 'Calibri';\n\t\t\t\tsrc: url(${Reader.Loader._res_data[t+"lib/fonts/calibrib.ttf"]});\n\t\t\t\tfont-style: normal;\n\t\t\t\tfont-weight : 700;\n\t\t\t}\n\n\t\t\t@font-face {\n\t\t\t\tfont-family: 'Calibri';\n\t\t\t\tsrc: url(${Reader.Loader._res_data[t+"lib/fonts/calibrii.ttf"]});\n\t\t\t\tfont-style: italic;\n\t\t\t\tfont-weight : 400;\n\t\t\t}\n\n\t\t\t@font-face {\n\t\t\t\tfont-family: 'Calibri';\n\t\t\t\tsrc: url(${Reader.Loader._res_data[t+"lib/fonts/calibri.ttf"]});\n\t\t\t\tfont-style: normal;\n\t\t\t\tfont-weight : 400;\n\t\t\t}\n\n\t\t\t/** Cambria */\n\n\t\t\t@font-face {\n\t\t\t\tfont-family: 'Cambria';\n\t\t\t\tsrc: url(${Reader.Loader._res_data[t+"lib/fonts/cambriab.ttf"]});\n\t\t\t\tfont-style: normal;\n\t\t\t\tfont-weight : 700;\n\t\t\t}\n\n\t\t\t@font-face {\n\t\t\t\tfont-family: 'Cambria';\n\t\t\t\tsrc: url(${Reader.Loader._res_data[t+"lib/fonts/cambriaz.ttf"]});\n\t\t\t\tfont-style: italic;\n\t\t\t\tfont-weight : 700;\n\t\t\t}\n\n\t\t\t@font-face {\n\t\t\t\tfont-family: 'Cambria';\n\t\t\t\tsrc: url(${Reader.Loader._res_data[t+"lib/fonts/cambriai.ttf"]});\n\t\t\t\tfont-style: italic;\n\t\t\t\tfont-weight : 400;\n\t\t\t}\n\n\t\t\t@font-face {\n\t\t\t\tfont-family: 'Cambria';\n\t\t\t\tsrc: url(${Reader.Loader._res_data[t+"lib/fonts/cambria.ttf"]});\n\t\t\t\tfont-style: normal;\n\t\t\t\tfont-weight : 400;\n\t\t\t}\n\n\t\t\t/** Caecilia */\n\n\t\t\t@font-face {\n\t\t\t\tfont-family: Caecilia;\n\t\t\t\tsrc: url(${Reader.Loader._res_data[t+"lib/fonts/caecilia.ttf"]});\n\t\t\t\tfont-weight : normal;\n\t\t\t}\n\n\t\t\t@font-face {\n\t\t\t\tfont-family: Caecilia;\n\t\t\t\tsrc: url(${Reader.Loader._res_data[t+"lib/fonts/caeciliab.ttf"]});\n\t\t\t\tfont-weight : bold;\n\t\t\t}\n\n\t\t\t@font-face {\n\t\t\t\tfont-family: Caecilia;\n\t\t\t\tsrc: url(${Reader.Loader._res_data[t+"lib/fonts/caeciliai.ttf"]});\n\t\t\t\tfont-style : italic;\n\t\t\t}\n\n\t\t\t/** Palatino */\n\n\t\t\t@font-face {\n\t\t\t\tfont-family: 'Palatino';\n\t\t\t\tsrc: url(${Reader.Loader._res_data[t+"lib/fonts/palab.ttf"]});\n\t\t\t\tfont-style: normal;\n\t\t\t\tfont-weight : 700;\n\t\t\t}\n\n\t\t\t@font-face {\n\t\t\t\tfont-family: 'Palatino';\n\t\t\t\tsrc: url(${Reader.Loader._res_data[t+"lib/fonts/palabi.ttf"]});\n\t\t\t\tfont-style: italic;\n\t\t\t\tfont-weight : 700;\n\t\t\t}\n\n\t\t\t@font-face {\n\t\t\t\tfont-family: 'Palatino';\n\t\t\t\tsrc: url(${Reader.Loader._res_data[t+"lib/fonts/palai.ttf"]});\n\t\t\t\tfont-style: italic;\n\t\t\t\tfont-weight : 400;\n\t\t\t}\n\n\t\t\t@font-face {\n\t\t\t\tfont-family: 'Palatino';\n\t\t\t\tsrc: url(${Reader.Loader._res_data[t+"lib/fonts/pala.ttf"]});\n\t\t\t\tfont-style: normal;\n\t\t\t\tfont-weight : 400;\n\t\t\t}\n\n\t\t\t/** Consolas */\n\n\t\t\t@font-face {\n\t\t\t\tfont-family: 'Consolas';\n\t\t\t\tsrc: url(${Reader.Loader._res_data[t+"lib/fonts/consolab.ttf"]});\n\t\t\t\tfont-style: normal;\n\t\t\t\tfont-weight : 700;\n\t\t\t}\n\n\t\t\t@font-face {\n\t\t\t\tfont-family: 'Consolas';\n\t\t\t\tsrc: url(${Reader.Loader._res_data[t+"lib/fonts/consolaz.ttf"]});\n\t\t\t\tfont-style: italic;\n\t\t\t\tfont-weight : 700;\n\t\t\t}\n\n\t\t\t@font-face {\n\t\t\t\tfont-family: 'Consolas';\n\t\t\t\tsrc: url(${Reader.Loader._res_data[t+"lib/fonts/consolai.ttf"]});\n\t\t\t\tfont-style: italic;\n\t\t\t\tfont-weight : 400;\n\t\t\t}\n\n\t\t\t@font-face {\n\t\t\t\tfont-family: 'Consolas';\n\t\t\t\tsrc: url(${Reader.Loader._res_data[t+"lib/fonts/consola.ttf"]});\n\t\t\t\tfont-style: normal;\n\t\t\t\tfont-weight : 400;\n\t\t\t}\n\n\t\t\t/** IBM Plex Mono */\n\n\t\t\t@font-face {\n\t\t\t\tfont-family: 'IBM Plex Mono';\n\t\t\t\tsrc: url(${Reader.Loader._res_data[t+"lib/fonts/IBMPlexMono-Bold.otf"]});\n\t\t\t\tfont-style: normal;\n\t\t\t\tfont-weight : 700;\n\t\t\t}\n\n\t\t\t@font-face {\n\t\t\t\tfont-family: 'IBM Plex Mono';\n\t\t\t\tsrc: url(${Reader.Loader._res_data[t+"lib/fonts/IBMPlexMono-BoldItalic.otf"]});\n\t\t\t\tfont-style: italic;\n\t\t\t\tfont-weight : 700;\n\t\t\t}\n\n\t\t\t@font-face {\n\t\t\t\tfont-family: 'IBM Plex Mono';\n\t\t\t\tsrc: url(${Reader.Loader._res_data[t+"lib/fonts/IBMPlexMono-TextItalic.otf"]});\n\t\t\t\tfont-style: italic;\n\t\t\t\tfont-weight : 400;\n\t\t\t}\n\n\t\t\t@font-face {\n\t\t\t\tfont-family: 'IBM Plex Mono';\n\t\t\t\tsrc: url(${Reader.Loader._res_data[t+"lib/fonts/IBMPlexMono-Text.otf"]});\n\t\t\t\tfont-style: normal;\n\t\t\t\tfont-weight : 400;\n\t\t\t}\n\t\t\t`},flattenTocSubItems:function(t,e){let o=[];return 3!=e&&(t.subitems&&$.each(t.subitems,(function(t,n){n._nest=e,o.push(n),o=o.concat(Reader.flattenTocSubItems(n,e+1))})),o)},flattenToc:function(t){if(this._flattened_toc)return this._flattened_toc;{let e=[];return $.each(t.navigation.toc,(function(t,o){o._nest=0,e.push(o),e=e.concat(Reader.flattenTocSubItems(o,1))})),this._flattened_toc=e,e}},generateTocBar:function(t,e){$(".spacer").html(""),$.each(e,(function(e,o){try{const e=t.spine.get(o.href).cfiBase,n=t.locations._locations.find((function(t){return-1!=t.indexOf(e)}));if(n){const e=Math.round(100*t.locations.percentageFromCfi(n));$(".spacer").append($("<div class='toc-bar-entry'>").attr("data-nest-level",o._nest).css("left",e+"%").css("_width",3-o._nest+"px").attr("title",o.label))}}catch(t){console.warn(t)}})),$(".spacer").append($("<div class='toc-bar-entry current-position'>")),Reader.updateTocBarPosition(t,t.rendition.currentLocation())},updateTocBarPosition:function(t,e){const o=Math.round(e.start.location/t.locations.length()*100);$(".toc-bar-entry.current-position").css("left",o+"%")},applyStyles:function(t){Promise.all([localforage.getItem("epube.fontSize"),localforage.getItem("epube.fontFamily"),localforage.getItem("epube.lineHeight"),localforage.getItem("epube.theme")]).then((function(e){const o=e[0]?e[0]+"px":"16px",n=e[1]?e[1]:"Arial",a=e[2]?e[2]+"%":"140%";console.log("style",n,o,a),console.log("applying default theme..."),window.book.rendition.themes.default({html:{"font-size":o,"font-family":"'"+n+"'","line-height":a,"text-align":"justify","text-indent":"1em"}}),t||(console.log("applying rendition themes..."),$.each(window.book.rendition.getContents(),(function(t,e){e.css("font-size",o),e.css("font-family","'"+n+"'"),e.css("line-height",a),e.css("text-align","justify")}))),Reader.applyTheme()}))},applyTheme:async function(){let t=await localforage.getItem("epube.theme")||"default";console.log("called for theme",t),"default"==t&&"undefined"!=typeof EpubeApp&&EpubeApp.isNightMode()&&(t="night"),console.log("setting main UI theme",t),$("body").attr("class","undefined"!=typeof EpubeApp?"is-epube-app":"").addClass("epube-reader theme-"+t).attr("data-is-loading","false"),"undefined"!=typeof EpubeApp&&window.setTimeout((function(){const t=window.getComputedStyle(document.querySelector("body"),null).getPropertyValue("background-color").match(/rgb\((\d{1,}), (\d{1,}), (\d{1,})\)/);t&&(console.log("sending bgcolor",t),EpubeApp.setStatusBarColor(parseInt(t[1]),parseInt(t[2]),parseInt(t[3])))}),250),window.book&&$.each(window.book.rendition.getContents(),(function(e,o){console.log("applying rendition theme",t,"to",o,o.document),$(o.document).find("body").attr("class","undefined"!=typeof EpubeApp?"is-epube-app":"").addClass("theme-"+t)}))},hotkeyHandler:function(t){try{if($(".modal").is(":visible"))return;39!=t.which&&32!=t.which&&34!=t.which||(t.preventDefault(),Reader.Page.next()),37!=t.which&&33!=t.which||(t.preventDefault(),Reader.Page.prev()),27==t.which&&(t.preventDefault(),Reader.showUI(!0))}catch(t){console.warn(t)}},resizeSideColumns:function(){let t=$("#reader").position().left;const e=$("#reader iframe")[0];e&&e.contentWindow.$&&(t+=parseInt(e.contentWindow.$("body").css("padding-left"))),$("#left, #right").width(t)},markAsRead:async function(){if(confirm("Mark book as read?")){const t=100,e=window.book.locations.cfiFromPercentage(1),o=(new Date).getTime();if(App.isOnline()){const n=await $.post("backend.php",{op:"storelastread",page:t,cfi:e,id:$.urlParam("id"),timestamp:o});$(".lastread_input").val(n.page+"%")}await localforage.setItem(Reader.cacheId("lastread"),{cfi:e,page:t,total:t,timestamp:o})}},close:async function(){const t=window.book.rendition.currentLocation().start.cfi,e=parseInt(100*window.book.locations.percentageFromCfi(t)),o=(new Date).getTime();await localforage.setItem(Reader.cacheId("lastread"),{cfi:t,page:e,total:100,timestamp:o}),App.isOnline()?$.post("backend.php",{op:"storelastread",id:$.urlParam("id"),page:e,cfi:t,timestamp:o},(function(){window.location=$.urlParam("rt")?"index.php?mode="+$.urlParam("rt"):"index.php"})).fail((function(){window.location="index.php"})):window.location="index.php"},cacheId:function(t){return"epube-book."+$.urlParam("b")+(t?"."+t:"")},toggleFullscreen:function(){if("undefined"!=typeof EpubeApp);else{const t=document.documentElement,e=document.webkitIsFullScreen||document.mozFullScreen||!1;t.requestFullScreen=t.requestFullScreen||t.webkitRequestFullScreen||t.mozRequestFullScreen||function(){return!1},document.cancelFullScreen=document.cancelFullScreen||document.webkitCancelFullScreen||document.mozCancelFullScreen||function(){return!1},e?document.cancelFullScreen():t.requestFullScreen()}},showUI:function(t){t?$(".header,.footer").fadeIn():$(".header,.footer").fadeOut()},toggleUI:function(){$(".header").is(":visible")?$(".header,.footer").fadeOut():$(".header,.footer").fadeIn()},lookupWord:async function(t,e){t=t.replace(/­/g,""),$(".dict_result").html("Loading, please wait..."),$("#dict-modal").modal("show");try{const o=await $.post("backend.php",{op:"define",word:t});o&&($(".dict_result").html(o.result.join("<br/>")),$(".dict_query").val(t),e&&e())}catch(t){console.error(t),$(".dict_result").html(`Network error while looking up word: ${t.responseText}.`)}},search:function(){const t=$(".search_input").val(),e=$(".search_results");e.html(""),t&&Promise.all(window.book.spine.spineItems.map(e=>e.load(window.book.load.bind(window.book)).then(e.find.bind(e,t)).finally(e.unload.bind(e)))).then(t=>Promise.resolve([].concat.apply([],t))).then((function(t){$.each(t,(function(t,o){const n=$("<a>").attr("href","#").html("<b class='pull-right'>"+window.book.locations.locationFromCfi(o.cfi)+"</b>"+o.excerpt).attr("data-cfi",o.cfi).attr("data-id",o.id).click((function(){window.book.rendition.display(n.attr("data-cfi"))}));e.append($("<li>").append(n))}))}))},Loader:{_res_data:[],init:async function(){const t=[];let e=!1;const o=await caches.open("epube-v3");(await o.keys()).forEach(o=>{if(!o.url.match("backend.php")){console.log("[loader] loading resource",o.url);const n=fetch(o.url).then(async t=>{if(t.ok){const e=new URL(t.url);if(e.searchParams.delete("ts"),t.url.match("\\.ttf|\\.otf")){const o=await t.blob();console.log("[loader] storing blob",e.href),Reader.Loader._res_data[e.toString()]=URL.createObjectURL(o)}else{const o=await t.text();console.log("[loader] storing text",e.href),Reader.Loader._res_data[e.toString()]=o}}else console.warn("[loader] failed for resource",o.url,t),$(".loading-message").html(`Unable to load resource.<br/><small>${o.url}</small>`),e=!0});t.push(n)}}),await Promise.allSettled(t),console.log("[loader] resource load complete, failed: ",e),e?Reader.applyTheme():Reader.initSecondStage()}},Page:{_moved_next:0,_prevent_lastread_timeout:!1,_prevent_lastread:!1,next:function(){window.book.rendition.next(),Reader.Page._moved_next+=1,"undefined"!=typeof EpubeApp?EpubeApp.showActionBar(!1):localforage.getItem("epube.keep-ui-visible").then((function(t){t||Reader.showUI(!1)}))},prev:function(){window.book.rendition.prev(),"undefined"!=typeof EpubeApp?EpubeApp.showActionBar(!1):localforage.getItem("epube.keep-ui-visible").then((function(t){t||Reader.showUI(!1)}))},openPrevious:async function(t){const e=$(t).attr("data-location-cfi");e&&await window.book.rendition.display(e),$(t).fadeOut()},blockLastReadUpdate:function(){console.log("blocking last read updates..."),Reader.Page._prevent_lastread_timeout&&window.clearTimeout(Reader.Page._prevent_lastread_timeout),Reader.Page._prevent_lastread_timeout=window.setTimeout(()=>{Reader.Page._prevent_lastread=!1,Reader.Page._prevent_lastread_timeout=!1,console.log("unblocked last read updates")},1e3),Reader.Page._prevent_lastread=!0},onRelocated:async function(t,e){const o=t.rendition;if(0==t.locations.length())return;await localforage.getItem("epube.enable-column-hacks")&&Reader.Page._moved_next>=20&&(console.log("forcing re-render because of column hacks"),o.onResized($("#reader").width()),Reader.Page._moved_next=0);const n=e.start.cfi,a=parseInt(100*t.locations.percentageFromCfi(n));$("#cur_page").text(Math.floor(e.start.location/10)),$("#total_pages").text(Math.floor(t.locations.length()/10)),$("#page_pct").text(parseInt(100*t.locations.percentageFromCfi(n))+"%"),Reader.updateTocBarPosition(t,e);const i=e.start.displayed;if(i&&($("#chapter_cur_page").text(i.page),$("#chapter_total_pages").text(i.total),i.total>0&&$("#chapter_pct").text(parseInt(i.page/i.total*100)+"%")),Reader.startup_finished&&Reader.last_stored_cfi!=n&&!Reader.Page._prevent_lastread){const t=(new Date).getTime();console.log("storing lastread",a,n,t),await localforage.setItem(Reader.cacheId("lastread"),{cfi:n,page:a,total:100,timestamp:t}),App.isOnline()&&(console.log("updating remote lastread",n),Reader.last_stored_cfi=n,$.post("backend.php",{op:"storelastread",id:$.urlParam("id"),page:a,cfi:n,timestamp:t}))}},clearLastRead:async function(){if(confirm("Clear stored last read location?")){const t=window.book.locations.length(),e=(new Date).getTime();if(App.isOnline()){const t=await $.post("backend.php",{op:"storelastread",page:-1,cfi:"",id:$.urlParam("id"),timestamp:e});$(".lastread_input").val(t.page+"%")}await localforage.setItem(Reader.cacheId("lastread"),{cfi:"",page:0,total:t,timestamp:e}),await window.book.rendition.display(window.book.locations.cfiFromPercentage(0))}},openLastRead:async function(){$(".loading-message").html("Opening last read page…");const t=window.book.rendition;if(!t)return void console.error("no rendition to work on");let e=!1;const o=await localforage.getItem(Reader.cacheId("lastread"))||{};if(console.log("got local lastread",o),o&&o.cfi){console.log("using local lastread cfi",o.cfi);try{await Reader.Page.moveToCfiVerify(t,o.cfi),e=!0}catch(t){console.warn(t)}}if(App.isOnline())try{const n=await $.post("backend.php",{op:"getlastread",id:$.urlParam("id")});console.log("got remote lastread",n),n&&n.cfi&&o.cfi!=n.cfi&&n.timestamp>=(o.timestamp||0)&&(console.log(`using remote lastread cfi ${n.cfi} (timestamp is newer or local timestamp is missing)`),await localforage.setItem(Reader.cacheId("lastread"),{cfi:n.cfi,page:n.page,total:n.total,timestamp:n.timestamp}),await Reader.Page.moveToCfiVerify(t,n.cfi),e=!0)}catch(t){console.log("unable to get remote lastread, continuing..."),console.warn(t)}e||t.display(),$(".loading").hide()},moveToCfiVerify:async function(t,e,o=3){for(let n=1;n<o;n++){Reader.Page.blockLastReadUpdate(),console.log(`trying to open ${e}: attempt ${n} of ${o}...`),await t.display(e);const a=t.currentLocation().start.cfi;if(console.log(`opened cfi ${a} expected ${e}`),a==e)return}}},Settings:{onThemeChanged:async function(t){const e=$(t).val();await localforage.setItem("epube.theme",e),Reader.applyTheme()},onLineHeightChanged:async function(t){const e=$(t).val();await localforage.setItem("epube.lineHeight",e),Reader.applyStyles()},onTextSizeChanged:async function(t){const e=$(t).val();await localforage.setItem("epube.fontSize",e),Reader.applyStyles()},onFontChanged:async function(t){const e=$(t).val();await localforage.setItem("epube.fontFamily",e),Reader.applyStyles()}}};function __get_reader(){return Reader}function __get_app(){return App} \ No newline at end of file
diff --git a/index.php b/index.php
index c49c69a..0788464 100644
--- a/index.php
+++ b/index.php
@@ -47,15 +47,8 @@
];
$check_files_mtime = array_merge($check_files_mtime, glob('lib/fonts/*'));
-
$check_files_mtime = array_filter($check_files_mtime, "file_exists");
- $last_mtime = array_reduce(
- array_map("filemtime", $check_files_mtime),
- function ($carry, $item) {
- return $item > $carry ? $item : $carry;
- }, 0);
-
$mode = htmlspecialchars($_REQUEST["mode"] ?? "");
$ldb = Db::pdo();
@@ -87,7 +80,6 @@
App.cached_urls = JSON.parse('<?= json_encode($check_files_mtime) ?>');
App.index_mode = "<?= $mode ?>";
App.version = "<?= Config::get_version(true) ?>";
- App.last_mtime = parseInt("<?= $last_mtime ?>");
App.init();
});
});
diff --git a/js/app.js b/js/app.js
index 3f44002..7903970 100644
--- a/js/app.js
+++ b/js/app.js
@@ -38,7 +38,6 @@ const Cookie = {
const App = {
_dl_progress_timeout: false,
index_mode: "",
- last_mtime: -1,
cached_urls: [],
version: "UNKNOWN",
csrf_token: "",
@@ -98,7 +97,6 @@ const App = {
}
if (event.data == 'refresh-finished') {
- localforage.setItem("epube.cache-timestamp", App.last_mtime);
localforage.setItem("epube.cache-version", App.version);
window.location.reload()
}
@@ -180,10 +178,10 @@ const App = {
},
refreshCache: function(force) {
if ('serviceWorker' in navigator) {
- localforage.getItem("epube.cache-timestamp").then(function(stamp) {
- console.log('stamp', stamp, 'last mtime', App.last_mtime, 'version', App.version);
+ localforage.getItem("epube.cache-version").then(function(version) {
+ console.log('local version', version, 'remote version', App.version);
- if (force || stamp != App.last_mtime) {
+ if (force || version != App.version) {
console.log('asking worker to refresh cache');
if (navigator.serviceWorker.controller) {