diff --git a/pb_public/index.html b/pb_public/index.html index d4f4c3b..d6a4f3e 100644 --- a/pb_public/index.html +++ b/pb_public/index.html @@ -1201,22 +1201,45 @@ async function loadDownloads(){ li.style.cssText="padding:12px;border:1px solid var(--line);border-radius:10px;"+ "margin-bottom:8px;background:var(--sunk);font-size:14px;list-style:none"; if (m.ok && m.data && m.data.available){ - // `releases.file` is a protected file: the path alone 403s, it needs a - // short-lived file token. Minted per link, exactly as the landing page does. - var t=await api("POST","/api/files/token",null); - var href=(t.ok && t.data && t.data.token) - ? m.data.downloadPath+"?token="+encodeURIComponent(t.data.token) : null; + // **The token is minted when the button is pressed, not when this list is + // built.** `releases.file` is protected, so the path needs a file token, and a + // file token lives 180 seconds — measured, not assumed. Baking one into the + // href at render time meant every download button died three minutes after + // the page loaded, permanently, until someone thought to reload. PocketBase + // answers an expired token with 404 "The requested resource wasn't found.", + // which reads like the file is gone rather than like "press it again". + // + // That is not a hypothetical: a friend hit it on the Windows build. The setup + // flow makes it near-certain, because it walks somebody through buying + // subscriptions and fetching a TMDB key before it points them here, which is + // many minutes, and the download tab may have been rendered at sign-in. li.innerHTML='
'+esc(p[1])+'
'+ esc(m.data.version||"")+" · "+esc(m.data.variant||"")+'
'+ - (href ? 'Stáhnout' - : 'odkaz se nepodařilo vytvořit')+'
'; + ''; any=true; } else { li.innerHTML=""+esc(p[1])+'
zatím nic ke stažení
'; } box.appendChild(li); } + // Wired after the rows exist, so each press mints its own token. `download=1` + // makes PocketBase send the file as an attachment instead of leaving the browser + // to decide what to do with a .zip or an .exe. + Array.prototype.forEach.call(box.querySelectorAll("button[data-dl]"), function(b){ + b.onclick=async function(){ + busy(b,true,"Připravuji…"); + var t=await api("POST","/api/files/token",null); + busy(b,false); + if(!(t.ok && t.data && t.data.token)){ + setMsg($("dlMsg"),"Odkaz se nepodařilo vytvořit. Zkus to prosím znovu.","err"); + return; + } + setMsg($("dlMsg"),""); + window.location.href = b.getAttribute("data-dl") + + "?token=" + encodeURIComponent(t.data.token) + "&download=1"; + }; + }); if (!any) setMsg($("dlMsg"),"Zatím není publikovaná žádná verze.",""); }