// PayToLaugh front end. // // NOTE ON THE TOKEN BELOW: it is public by construction. A static page cannot // keep a secret, so the endpoint behind it is built to be safe in public // hands. It reads and writes small records only and cannot spend money. // Script and video generation are deliberately NOT reachable from here. // // NOTE ON "LOGIN": an email address identifies you, it does not authenticate // you. Anyone who knows an address can see that account. Temporary, by // agreement, until real auth lands. var API = "https://api.corben.world/functions/da0474ea-4e56-405c-9f0d-35c3e4037a69/invoke" + "?token=97cd624cd2bd6a74eb692a940e71851f"; async function api(action, payload) { var body = Object.assign({ action: action }, payload || {}); var res; try { res = await fetch(API, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body) }); } catch (e) { return { ok: false, error: "Could not reach the server. Check your connection and try again." }; } var outer; try { outer = await res.json(); } catch (e) { return { ok: false, error: "The server sent something unreadable." }; } // The invoke route wraps the function result. return outer && outer.result ? outer.result : outer; } var Session = { key: "ptl_email", nameKey: "ptl_name", get: function () { try { return localStorage.getItem(this.key); } catch (e) { return null; } }, name: function () { try { return localStorage.getItem(this.nameKey) || ""; } catch (e) { return ""; } }, set: function (email, name) { try { localStorage.setItem(this.key, email); if (name) localStorage.setItem(this.nameKey, name); } catch (e) {} }, clear: function () { try { localStorage.removeItem(this.key); localStorage.removeItem(this.nameKey); } catch (e) {} } }; function esc(s) { return String(s == null ? "" : s).replace(/[&<>\"']/g, function (c) { return { "&": "&", "<": "<", ">": ">", '\"': """, "'": "'" }[c]; }); } function navBar(current) { var email = Session.get(); var links = [["/", "Home", "home"], ["/create.html", "New video", "create"], ["/videos.html", "My videos", "videos"]]; var html = ''; document.body.insertAdjacentHTML("afterbegin", html); var b = document.getElementById("ptl-signout"); if (b) b.onclick = function () { Session.clear(); location.href = "/register.html"; }; } // Pages that need an identity send you to sign in rather than failing oddly. function requireSession() { var e = Session.get(); if (!e) { location.href = "/register.html?next=" + encodeURIComponent(location.pathname); return null; } return e; } function showMsg(id, text, kind) { var el = document.getElementById(id); if (!el) return; el.className = "msg " + (kind || "err"); el.textContent = text; } function hideMsg(id) { var el = document.getElementById(id); if (el) el.className = "msg"; } // Mirrors the server's arithmetic exactly: $0.40 per 8s clip plus $0.17 for // script and plate, at a 5x markup. If one changes, change both. function priceFor(segments) { var cost = segments * 0.40 + 0.17; return { cost: cost, price: Math.round(cost * 5 * 100) / 100, seconds: segments * 8 }; }