diff --git a/trailer.html b/trailer.html index e6677e5..5d230cb 100644 --- a/trailer.html +++ b/trailer.html @@ -17,11 +17,14 @@ .head h2{margin:0;font-size:22px} .tag{color:var(--muted);font-style:italic} .facts{color:var(--muted);font-size:13px;margin:2px 0 18px} - .cast{display:flex;flex-wrap:wrap;gap:10px;margin:0 0 22px} - .ch{border:1px solid var(--line);border-radius:10px;padding:9px 12px;font-size:13px;max-width:330px} + .cast{display:flex;flex-wrap:wrap;gap:14px;margin:0 0 22px} + .ch{border:1px solid var(--line);border-radius:10px;padding:10px;font-size:13px;width:250px} .ch b{display:block} .ch .vo{color:var(--muted);font-size:12px} - .ch .ap{color:var(--muted);font-size:12px;margin-top:3px} + .ch .ap{color:var(--muted);font-size:12px;margin-top:4px} + .sheets{display:flex;gap:5px;margin-bottom:8px} + .sheets img{width:33%;border-radius:6px;border:1px solid var(--line);display:block; + aspect-ratio:16/9;object-fit:cover} .shot{border-top:1px solid var(--line);padding:16px 0;display:flex;gap:16px} .shot .num{width:34px;flex:none;color:var(--muted);font-variant-numeric:tabular-nums} .shot .body{flex:1;min-width:0} @@ -83,36 +86,51 @@ if (!runId) { showMsg("msg", "No run was named in the link."); return; } - // ------------------------------------------------------------ polling + // A draft is busy while it is being written or drawn. Both are minutes long + // and both report progress on the row, so one poll covers them. + function busyState(d) { + var s = String(d.draw_state || ""); + return d.state === "writing" || (s && !/^(drawn|failed)/.test(s)); + } - async function load() { + async function load(repaint) { var r = await api("run_status", { run_id: runId }); if (!r.ok) { showMsg("msg", r.error || "Could not load that run."); return; } + var wasBusy = DRAFTS.length && DRAFTS.some(busyState); RUN = r.run; DRAFTS = r.drafts || []; document.getElementById("title").textContent = RUN.book_title || "Trailers"; document.getElementById("sub").textContent = sub(); if (!CUR && DRAFTS.length) CUR = DRAFTS[0].id; paintTabs(); - var busy = DRAFTS.some(function (d) { return d.state === "writing"; }); - if (busy && !timer) timer = setInterval(load, 4000); + + var busy = DRAFTS.some(busyState); + if (busy && !timer) timer = setInterval(load, 5000); if (!busy && timer) { clearInterval(timer); timer = null; } - if (!busy) openTab(CUR); - else paintWriting(); + + var me = DRAFTS.filter(function (d) { return d.id === CUR; })[0]; + if (me && me.state === "writing") { paintWriting(); return; } + // Repaint when asked, on first paint, or when work has just finished. + if (repaint !== false && (wasBusy || !document.querySelector(".shot"))) openTab(CUR); + else paintBar(); } function sub() { var bits = []; if (RUN.stage) bits.push(RUN.stage); bits.push(DRAFTS.length + " writer" + (DRAFTS.length === 1 ? "" : "s")); - if (RUN.cost_usd) bits.push("$" + Number(RUN.cost_usd).toFixed(2) + " so far"); + var spent = DRAFTS.reduce(function (a, d) { + return a + Number(d.write_usd || 0) + Number(d.draw_usd || 0); }, 0); + if (spent) bits.push("$" + spent.toFixed(2) + " so far"); if (RUN.created_at) bits.push(when(RUN.created_at)); return bits.join(" · "); } function paintTabs() { document.getElementById("tabs").innerHTML = DRAFTS.map(function (d) { + var s = String(d.draw_state || ""); var extra = d.state === "writing" ? 'writing…' : d.state === "failed" ? 'failed' + : (s && !/^(drawn|failed)/.test(s)) ? '' + esc(s) + '' : d.score ? '' + d.score + '' : ''; return 'Cast sheets first, then every shot. ' + + 'This takes a few minutes.'; + } + if (/^drawn/.test(s)) { + return '' + + '' + esc(s) + + (meta.draw_usd ? ' · $' + Number(meta.draw_usd).toFixed(2) + ' spent' : '') + + ''; + } + return '' + + '' + imgs + ' pictures — ' + cast + + ' cast sheets and ' + shots + ' shots, opening and closing.' + + (s === "failed" && meta.note ? '' + esc(meta.note) + '' : ''); + } + + function paintBar() { + var el = document.querySelector(".bar"); + var meta = DRAFTS.filter(function (d) { return d.id === CUR; })[0]; + if (el && meta) el.innerHTML = drawBtn(meta); + } + function paneHtml(meta, draft) { var p = PKG, shots = p.shots || [], cast = p.characters || []; var voice = {}; cast.forEach(function (c) { voice[c.id] = c; }); var secs = shots.reduce(function (a, s) { return a + (Number(s.edit_seconds) || 0); }, 0); - // Drawing is priced off what this writer actually wrote, not an estimate: - // three sheets a character plus an opening and a closing frame a shot. - var imgs = cast.length * 3 + shots.length * 2; - var price = imgs * 0.068; var head = '