admin: show the delivery direction, the request actually sent, and a redub switch

This commit is contained in:
gator 2026-09-10 01:15:49 +00:00
parent f6f1335fff
commit 30da437300

View file

@ -68,11 +68,22 @@ function shotHtml(s) {
+ '<p style="margin:0 0 6px">' + esc(s.line || "") + '</p>' + '<p style="margin:0 0 6px">' + esc(s.line || "") + '</p>'
+ '<div class="kv"><span' + (over ? ' class="warnw"' : '') + '>' + s.words + ' words' + '<div class="kv"><span' + (over ? ' class="warnw"' : '') + '>' + s.words + ' words'
+ (over ? ' (over 18)' : '') + '</span> · camera: ' + esc(s.camera || "—") + '</div>' + (over ? ' (over 18)' : '') + '</span> · camera: ' + esc(s.camera || "—") + '</div>'
// The writer's performance direction. It used to reach the previz and
// never Veo, so a line written as "building outrage" was filmed flat.
// Showing both halves is the point: what was asked for, and what went.
+ '<div class="kv">delivery: ' + (s.delivery_sent
? '<b>' + esc(s.delivery_sent) + '</b> — sent to Veo'
: (s.delivery
? '<span class="warnw">' + esc(s.delivery) + ' — written but NOT sent</span>'
: 'none written for this line')) + '</div>'
// A redub that failed falls back to Veo's own audio on purpose. That is // A redub that failed falls back to Veo's own audio on purpose. That is
// the right behaviour, but it must not be silent. // the right behaviour, but it must not be silent. Deliberately skipping
// it is a third state and must not read as the failure.
+ '<div class="kv">voice: ' + (s.voice_used + '<div class="kv">voice: ' + (s.voice_used
? esc(s.voice_used) + ' (redubbed)' ? esc(s.voice_used) + ' (redubbed)'
: '<span class="warnw">Veo original, not redubbed</span>') + '</div>' : (s.redub_skipped
? 'Veo original — redub switched off for this run'
: '<span class="warnw">Veo original, not redubbed</span>')) + '</div>'
// The likeness chain, end to end: the owner's photograph, then the // The likeness chain, end to end: the owner's photograph, then the
// opening frame built from it, which is what Veo actually receives. If // opening frame built from it, which is what Veo actually receives. If
// the frame is missing, Veo saw only the written description. // the frame is missing, Veo saw only the written description.
@ -103,6 +114,13 @@ function shotHtml(s) {
+ (s.prompt_sent + (s.prompt_sent
? '<details><summary>Exact prompt sent</summary><pre>' + esc(s.prompt_sent) + '</pre></details>' ? '<details><summary>Exact prompt sent</summary><pre>' + esc(s.prompt_sent) + '</pre></details>'
: '<div class="kv">no prompt recorded (filmed before prompts were stored)</div>') : '<div class="kv">no prompt recorded (filmed before prompts were stored)</div>')
// The prompt and the request are not the same claim. An earlier version of
// video_render validated its images and then posted only the prompt, which
// read as working code for weeks. This is the body as it went on the wire.
+ (s.request_sent
? '<details><summary>The request body actually POSTed</summary><pre>'
+ esc(s.request_sent) + '</pre></details>'
: '')
+ '</div>'; + '</div>';
} }
@ -130,6 +148,14 @@ function projHtml(p) {
+ '<b>source</b> <a href="' + esc(p.source_url || "#") + '" target="_blank" rel="noopener nofollow">' + esc((p.source_url || "").slice(0, 70)) + '</a>' + '<b>source</b> <a href="' + esc(p.source_url || "#") + '" target="_blank" rel="noopener nofollow">' + esc((p.source_url || "").slice(0, 70)) + '</a>'
+ (p.film_note ? '<br><span class="warnw"><b>note</b> ' + esc(p.film_note) + '</span>' : '') + (p.film_note ? '<br><span class="warnw"><b>note</b> ' + esc(p.film_note) + '</span>' : '')
+ '</div>' + '</div>'
// Operator switch, for hearing the same script both ways. Not a customer
// control: the server refuses it to anyone without the admin role.
+ '<div class="kv" style="margin-top:10px">redub on the next film: <b>'
+ (p.skip_redub ? 'OFF — Veo keeps its own voice' : 'on') + '</b> '
+ '<button type="button" class="btn" style="padding:4px 10px;font-size:12px;margin-left:8px" '
+ 'data-redub="' + esc(p.id) + '" data-want="' + (p.skip_redub ? '0' : '1') + '">'
+ (p.skip_redub ? 'Put the redub back on' : 'Film the next one without it')
+ '</button></div>'
+ (p.owner_notes ? '<p class="kv" style="margin-top:10px"><b>notes</b> ' + esc(p.owner_notes) + '</p>' : '') + (p.owner_notes ? '<p class="kv" style="margin-top:10px"><b>notes</b> ' + esc(p.owner_notes) + '</p>' : '')
+ '</div></div>' + '</div></div>'
+ (p.full_text ? '<details><summary>Full piece as written</summary><pre>' + esc(p.full_text) + '</pre></details>' : '') + (p.full_text ? '<details><summary>Full piece as written</summary><pre>' + esc(p.full_text) + '</pre></details>' : '')
@ -162,6 +188,26 @@ async function load() {
+ '<div><b>' + pct + '%</b><span>took first draft</span></div>' + '<div><b>' + pct + '%</b><span>took first draft</span></div>'
+ '</div>' + '</div>'
+ (r.projects || []).map(projHtml).join(""); + (r.projects || []).map(projHtml).join("");
// Delegated, because the list is re-rendered wholesale on every load.
document.getElementById("out").onclick = async function (ev) {
var b = ev.target.closest ? ev.target.closest("[data-redub]") : null;
if (!b) return;
b.disabled = true;
var was = b.textContent;
b.textContent = "Saving...";
var res = await api("set_film_options", {
project_id: b.getAttribute("data-redub"),
skip_redub: b.getAttribute("data-want") === "1"
});
if (!res.ok) {
showMsg("msg", res.error || "Could not change that.");
b.disabled = false;
b.textContent = was;
return;
}
load();
};
} }
document.getElementById("go").onclick = function () { document.getElementById("go").onclick = function () {