From 63157772c547d6ceefeca696f85986f23b1a9fbf Mon Sep 17 00:00:00 2001 From: lelo Date: Fri, 27 Feb 2026 11:41:53 +0000 Subject: [PATCH] fix Download original --- static/gallery.css | 24 +++++++++++++++---- static/gallery.js | 60 +++++++++++++++++++++++++++++++++++++++++----- templates/app.html | 4 ++-- 3 files changed, 75 insertions(+), 13 deletions(-) diff --git a/static/gallery.css b/static/gallery.css index 2f01c69..e71c88a 100644 --- a/static/gallery.css +++ b/static/gallery.css @@ -39,20 +39,29 @@ cursor: pointer; } - /* Close Button positioning */ + /* Close Button */ #gallery-close { position: fixed; top: 20px; right: 20px; - font-size: 24px; + width: 36px; + height: 36px; + border-radius: 50%; + border: 1px solid rgba(255, 255, 255, 0.25); + background: rgba(0, 0, 0, 0.6); color: #fff; + display: grid; + place-items: center; cursor: pointer; - z-index: 100; - background: transparent; - border: none; + z-index: 120; + font-size: 1.1rem; padding: 0; margin: 0; } + + #gallery-close:hover { + background: rgba(40, 40, 40, 0.85); + } /* Loader for gallery */ #loader-container { @@ -94,11 +103,14 @@ padding: 1rem; cursor: pointer; z-index: 10; + transition: opacity 0.4s ease; } .gallery-prev { left: 20px; } .gallery-next { right: 20px; } + .gallery-nav.nav-hidden { opacity: 0; } + #gallery-info { position: fixed; top: 20px; @@ -225,6 +237,8 @@ cursor: pointer; z-index: 120; font-size: 1.2rem; + line-height: 1; + padding: 0 0 0 2px; /* optical compensation for ▶ glyph whitespace */ --autoplay-duration: 5s; --play-progress: 0deg; overflow: visible; diff --git a/static/gallery.js b/static/gallery.js index dd7c4eb..85a846c 100644 --- a/static/gallery.js +++ b/static/gallery.js @@ -7,6 +7,7 @@ let exifAbortController = null; let isGalleryLoading = false; let autoPlayTimer = null; let isAutoPlay = false; +let navHideTimer = null; const AUTO_PLAY_INTERVAL_MS = 5000; let pendingAutoAdvance = false; @@ -197,12 +198,13 @@ function updateDownloadLink(relUrl) { if (!relUrl) { downloadBtn.removeAttribute('href'); downloadBtn.removeAttribute('download'); + downloadBtn.removeAttribute('data-relurl'); return; } - const parts = relUrl.split('/'); - const filename = parts[parts.length - 1] || relUrl; - downloadBtn.href = '/media/' + encodeGalleryPath(relUrl) + '?download=true'; - downloadBtn.setAttribute('download', filename); + // Store relUrl for the click handler (which fetches a short-lived token) + downloadBtn.dataset.relurl = relUrl; + downloadBtn.removeAttribute('href'); + downloadBtn.removeAttribute('download'); } function updateNextButtonState() { @@ -216,11 +218,20 @@ function updateNextButtonState() { nextButton.setAttribute('aria-label', atLastImage ? 'Close gallery' : 'Next image'); } +function showGalleryNav() { + clearTimeout(navHideTimer); + document.querySelectorAll('.gallery-nav').forEach(btn => btn.classList.remove('nav-hidden')); + navHideTimer = setTimeout(() => { + document.querySelectorAll('.gallery-nav').forEach(btn => btn.classList.add('nav-hidden')); + }, 1000); +} + function openGalleryModal(relUrl) { document.body.style.overflow = 'hidden'; // Disable background scrolling. currentGalleryIndex = currentGalleryImages.indexOf(relUrl); showGalleryImage(relUrl); document.getElementById('gallery-modal').style.display = 'flex'; + showGalleryNav(); } function showGalleryImage(relUrl) { @@ -334,6 +345,8 @@ function preloadNextImage() { } function closeGalleryModal() { + clearTimeout(navHideTimer); + document.querySelectorAll('.gallery-nav').forEach(btn => btn.classList.remove('nav-hidden')); document.getElementById('gallery-modal').style.display = 'none'; isGalleryLoading = false; setAutoPlay(false); @@ -388,7 +401,10 @@ function initGallerySwipe() { let touchEndX = 0; const galleryModal = document.getElementById('gallery-modal'); + galleryModal.addEventListener('mousemove', showGalleryNav, false); + galleryModal.addEventListener('touchstart', function(e) { + showGalleryNav(); // If more than one finger is on screen, ignore swipe tracking. if (e.touches.length > 1) { return; @@ -434,7 +450,7 @@ function setAutoPlay(active) { const playButton = document.getElementById('gallery-play'); isAutoPlay = active; if (playButton) { - playButton.textContent = active ? '||' : '>'; + playButton.textContent = active ? '\u23F8' : '\u25B6'; playButton.setAttribute('aria-pressed', active ? 'true' : 'false'); playButton.classList.toggle('playing', active); } @@ -598,8 +614,40 @@ function initGalleryControls() { const downloadButton = document.getElementById('gallery-download'); if (downloadButton) { - downloadButton.addEventListener('click', function (e) { + downloadButton.addEventListener('click', async function (e) { + e.preventDefault(); e.stopPropagation(); + + const relUrl = downloadButton.dataset.relurl; + if (!relUrl) return; + + const encodedSubpath = relUrl + .replace(/^\/+/, '') + .split('/') + .map(segment => encodeURIComponent(decodeURIComponent(segment))) + .join('/'); + + // Fetch a short-lived download token (works in Telegram's internal browser) + let tokenizedUrl; + try { + const resp = await fetch(`/create_dltoken/${encodedSubpath}`); + if (!resp.ok) return; + tokenizedUrl = (await resp.text()).trim(); + } catch { + return; + } + + if (!tokenizedUrl) return; + + // Append download=true so the server returns the full-size original as attachment + const sep = tokenizedUrl.includes('?') ? '&' : '?'; + const downloadUrl = new URL(tokenizedUrl + sep + 'download=true', window.location.href); + + const a = document.createElement('a'); + a.href = downloadUrl.toString(); + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); }); } diff --git a/templates/app.html b/templates/app.html index bc64cdd..719b44c 100644 --- a/templates/app.html +++ b/templates/app.html @@ -204,13 +204,13 @@