diff --git a/dlibrary/dlibrary.py b/dlibrary/dlibrary.py index f6d4e7a..07a584b 100755 --- a/dlibrary/dlibrary.py +++ b/dlibrary/dlibrary.py @@ -373,11 +373,14 @@ def collate(args): collation_staging_area = args.destdir / 'site' / 'images-staging' collation_staging_area.mkdir(parents=True) + collation_area = args.destdir / 'site' / 'images' + collation_area.mkdir(parents=True, exist_ok=True) + for work_path in extraction_dir.iterdir(): work_id = work_path.name - collation_dir = args.destdir / 'site' / 'images' / work_id - if collation_dir.exists(): + work_collation_dir = collation_area / work_id + if work_collation_dir.exists(): continue virtual = cur.execute("SELECT virtual FROM works WHERE id = ?", (work_id,)).fetchone() @@ -389,7 +392,7 @@ def collate(args): pages_collated = collate_from_paths([hint_map.get(work_id, work_path)], work_staging_dir, 0, []) if pages_collated: print(f'Collated {pages_collated} pages for {work_id}') - work_staging_dir.rename(collation_dir) + work_staging_dir.rename(work_collation_dir) else: if work_staging_dir.is_dir(): for f in work_staging_dir.iterdir(): @@ -603,13 +606,16 @@ def manual_collate(args): else: groups = [[extraction_dir / work_id]] - collation_dir = args.destdir / 'site' / 'images' / work_id - if collation_dir.exists(): - if len(list(collation_dir.iterdir())) > 0: + collation_area = args.destdir / 'site' / 'images' + collation_area.mkdir(parents=True, exist_ok=True) + + work_collation_dir = collation_area / work_id + if work_collation_dir.exists(): + if len(list(work_collation_dir.iterdir())) > 0: print(f'Collation directory already exists!') return else: - collation_dir.rmdir() + work_collation_dir.rmdir() nonexistent = [path for group in (groups + [exclusions]) for path in group if not path.exists()] if len(nonexistent) > 0: @@ -637,7 +643,7 @@ def manual_collate(args): if pages_collated: print(f'Collated {pages_collated} pages for {work_id}') - work_staging_dir.rename(collation_dir) + work_staging_dir.rename(work_collation_dir) else: for f in work_staging_dir.iterdir(): f.unlink() diff --git a/dlibrary/static/viewer.css b/dlibrary/static/viewer.css index c78f3ab..36c62ed 100644 --- a/dlibrary/static/viewer.css +++ b/dlibrary/static/viewer.css @@ -8,6 +8,8 @@ html, body { #controls { opacity: 0.8; animation: 2s linear forwards fade; + position: relative; + z-index: 300; } @keyframes fade { @@ -62,20 +64,28 @@ html, body { bottom: 0px; } -#viewer-images { - display: none; -} - -#image-container { +.image-container img { + position: fixed; + left: 0; + top: 0; height: 100vh; width: 100vw; - background-size: contain; - background-repeat: no-repeat; - background-position: center; + object-fit: contain; + object-position: 50% 50%; + background-color: #111; +} + +#current-image img { + z-index: 100; +} + +#preload-images img { + z-index: 0; } #page-num, #duration { position: fixed; + z-index: 200; font-size: 14pt; top: 10px; font-weight: bold; @@ -110,4 +120,5 @@ html, body { position: fixed; top: 0; left: 0; + z-index: 400; } diff --git a/dlibrary/static/viewer.js b/dlibrary/static/viewer.js index 1f8fc81..b1a47b2 100644 --- a/dlibrary/static/viewer.js +++ b/dlibrary/static/viewer.js @@ -1,31 +1,43 @@ -const PROGRESS_UPDATE_INTERVAL = 50; +const PRELOAD_BACKWARD = 2; +const PRELOAD_FORWARD = 8; document.addEventListener('DOMContentLoaded', () => { - const pages = Array.from(document.querySelectorAll('img.viewer-image')); + const currentImage = document.getElementById('current-image'); + const preloadImages = document.getElementById('preload-images'); + let currentPage = parseInt(localStorage.getItem(`${WORK_ID}-currentPage`)) || 0; let duration = parseInt(localStorage.getItem(`${WORK_ID}-duration`)) || 10; - let paused = true; - let interval; - let elapsed = 0; let rtl = (localStorage.getItem(`${WORK_ID}-rtl`) !== "false"); + let paused = true; - function startTimer() { - if (interval) { - clearInterval(interval); + let elapsed = 0; + let timerLastRun = null; + let timerAnimationRequestID = null; + + function requestTimer() { + timerAnimationRequestID = window.requestAnimationFrame(runTimer); + } + + function runTimer(now) { + if (paused) { + return; } - interval = setInterval( - function () { - if (paused) { - return; - } - elapsed += PROGRESS_UPDATE_INTERVAL; - if (elapsed >= duration*1000) { - changePage(currentPage + 1); - } - updateBar(); - }, - PROGRESS_UPDATE_INTERVAL, - ); + + if (timerLastRun === null) { + elapsed = 0; + } else { + elapsed += now - timerLastRun; + } + timerLastRun = now; + + if (elapsed >= duration*1000) { + changePage(currentPage + 1); + elapsed = 0; + } + + updateBar(); + + requestTimer(); } const progressBar = document.getElementById('progress'); @@ -34,34 +46,54 @@ document.addEventListener('DOMContentLoaded', () => { } function stopTimer() { - if (interval) { - clearInterval(interval); - interval = null; + if (timerAnimationRequestID) { + window.cancelAnimationFrame(timerAnimationRequestID); + timerAnimationRequestID = null; } + timerLastRun = null; elapsed = 0; updateBar(); } + function imageSrc(s) { + const img = new Image(); + img.src = s; + return img; + } + + function preload() { + if (!currentImage.getElementsByTagName('img')[0].complete) { + setTimeout(preload, 50); + return; + } + + preloadImages.replaceChildren(...( + IMAGES.slice( + Math.max(currentPage - PRELOAD_BACKWARD, 0), + currentPage + PRELOAD_FORWARD + 1, + ).map(imageSrc) + )); + } + function changePage(pageNum) { elapsed = 0; + updateBar(); - const previous = pages[currentPage]; - const current = pages[pageNum]; + const previous = IMAGES[currentPage]; + const current = IMAGES[pageNum]; if (current == null) { return; } - previous.classList.remove('current'); - current.classList.add('current'); - currentPage = pageNum; localStorage.setItem(`${WORK_ID}-currentPage`, currentPage); - const display = document.getElementById('image-container'); - display.style.backgroundImage = `url("${current.src}")`; + currentImage.replaceChildren(imageSrc(current)); document.getElementById('current-page').innerText = (pageNum + 1).toLocaleString(); + + setTimeout(preload, 1); } const durationDisplay = document.getElementById('duration'); @@ -76,7 +108,7 @@ document.addEventListener('DOMContentLoaded', () => { stopTimer(); } else { durationDisplay.style.textDecoration = ""; - startTimer(); + requestTimer(); } } @@ -102,7 +134,7 @@ document.addEventListener('DOMContentLoaded', () => { function exitToWork() { changeDuration(duration, true); - if (currentPage === pages.length - 1) { + if (currentPage === IMAGES.length - 1) { localStorage.removeItem(`${WORK_ID}-currentPage`); } window.location.href = `../${INDEX}`; diff --git a/dlibrary/templates/viewer.html b/dlibrary/templates/viewer.html index a2d61fd..aee53e8 100644 --- a/dlibrary/templates/viewer.html +++ b/dlibrary/templates/viewer.html @@ -5,15 +5,15 @@ {% endblock %} {% block body %} -
- {% for filename in images %} - - {% endfor %} -
@@ -46,5 +46,6 @@ -
+
+
{% endblock %}