script: rebuild part 5 of 6
This commit is contained in:
parent
7ce21f6621
commit
dd1ad70fb7
1 changed files with 198 additions and 0 deletions
198
script.html
198
script.html
|
|
@ -996,4 +996,202 @@ function pzPaint(lines) {
|
||||||
: ''))
|
: ''))
|
||||||
+ (over.length
|
+ (over.length
|
||||||
? '<div class="warn" style="margin-top:12px">Shot' + (over.length > 1 ? 's ' : ' ')
|
? '<div class="warn" style="margin-top:12px">Shot' + (over.length > 1 ? 's ' : ' ')
|
||||||
|
+ over.map(function (x) { return x.index; }).join(", ")
|
||||||
|
+ ' will not fit in eight seconds once filmed: '
|
||||||
|
+ over.map(function (x) { return x.index + " would run " + (x.seconds * FILMED).toFixed(1) + "s"; }).join(", ")
|
||||||
|
+ '. Trim those lines before filming.</div>'
|
||||||
|
: '')
|
||||||
|
+ '<div style="margin-top:14px">'
|
||||||
|
+ PZ.map(function (x) {
|
||||||
|
var f = (x.seconds || 0) * FILMED;
|
||||||
|
return '<div class="foot" style="padding:6px 0;border-top:1px solid var(--line)">'
|
||||||
|
+ 'shot ' + x.index + ' · ' + x.seconds.toFixed(1) + 's spoken, ~'
|
||||||
|
+ f.toFixed(1) + 's filmed'
|
||||||
|
+ (f > 8 ? ' <span style="color:var(--accent2)">over</span>' : '')
|
||||||
|
+ ' · ' + esc(x.line.slice(0, 60)) + '</div>';
|
||||||
|
}).join("")
|
||||||
|
+ '</div>';
|
||||||
|
|
||||||
|
var img = document.getElementById("pzimg"),
|
||||||
|
aud = document.getElementById("pzaud"),
|
||||||
|
btn = document.getElementById("pzplay"),
|
||||||
|
where = document.getElementById("pzwhere");
|
||||||
|
|
||||||
|
function stop() {
|
||||||
|
aud.pause();
|
||||||
|
if (PZTIMER) { clearTimeout(PZTIMER); PZTIMER = null; }
|
||||||
|
btn.innerHTML = "▶ Play the run-through";
|
||||||
|
}
|
||||||
|
|
||||||
|
function playFrom(i) {
|
||||||
|
if (i >= PZ.length) { stop(); return; }
|
||||||
|
var x = PZ[i];
|
||||||
|
img.src = x.plate || "";
|
||||||
|
where.textContent = "shot " + x.index + " of " + PZ.length + " · " + x.seconds.toFixed(1) + "s";
|
||||||
|
aud.src = x.url;
|
||||||
|
aud.onended = function () { playFrom(i + 1); };
|
||||||
|
aud.play().catch(function () { stop(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
btn.onclick = function () {
|
||||||
|
if (!aud.paused) { stop(); return; }
|
||||||
|
btn.innerHTML = "▮▮ Stop";
|
||||||
|
playFrom(0);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function bindAlign() {
|
||||||
|
var b = document.getElementById("alignbtn");
|
||||||
|
if (!b) return;
|
||||||
|
var out = document.getElementById("alignout");
|
||||||
|
|
||||||
|
function paint(r) {
|
||||||
|
var bought = ((DATA && DATA.script && DATA.script.segments) || []).length * 8;
|
||||||
|
var filmed = r.filmed || 0;
|
||||||
|
out.innerHTML = '<p class="foot" style="margin:0 0 8px">Measured: '
|
||||||
|
+ (r.spoken || 0).toFixed(1) + 's spoken, about ' + filmed.toFixed(1)
|
||||||
|
+ 's filmed, against ' + bought + 's of shots.</p>'
|
||||||
|
+ (r.audio ? '<audio controls src="' + esc(r.audio) + '" style="width:100%;max-width:420px"></audio>' : '')
|
||||||
|
+ (r.shots || []).map(function (s) {
|
||||||
|
var fit = Math.abs((s.filmed || 0) - 8) <= 1.2;
|
||||||
|
return '<div class="foot" style="padding:6px 0;border-top:1px solid var(--line)">'
|
||||||
|
+ 'shot ' + s.index + ' · ' + (s.start || 0).toFixed(1) + '-'
|
||||||
|
+ (s.end || 0).toFixed(1) + 's spoken · ~' + (s.filmed || 0).toFixed(1) + 's filmed'
|
||||||
|
+ (fit ? '' : ' <span style="color:var(--accent2)">off the clock</span>')
|
||||||
|
+ '<br>' + esc(s.line || "") + '</div>';
|
||||||
|
}).join("")
|
||||||
|
+ (filmed < bought - 1.5
|
||||||
|
? '<div class="warn" style="margin-top:12px">The whole piece only runs about '
|
||||||
|
+ filmed.toFixed(1) + ' seconds filmed, but ' + bought + ' seconds are being shot. '
|
||||||
|
+ 'No arrangement of these words fills the video — it needs more written, or a '
|
||||||
|
+ 'shorter length.</div>'
|
||||||
|
: '')
|
||||||
|
+ (filmed > bought + 1.5
|
||||||
|
? '<div class="warn" style="margin-top:12px">The whole piece runs about '
|
||||||
|
+ filmed.toFixed(1) + ' seconds filmed against ' + bought + ' seconds of video, so the '
|
||||||
|
+ 'end would be cut off. Trim it, or buy more length.</div>'
|
||||||
|
: '');
|
||||||
|
}
|
||||||
|
|
||||||
|
b.onclick = async function () {
|
||||||
|
hideMsg("msg");
|
||||||
|
b.disabled = true; b.textContent = "Measuring…";
|
||||||
|
var r = await api("align_script", { email: email, project_id: pid, refresh: true });
|
||||||
|
if (r.ok && r.pending) {
|
||||||
|
var waited = 0;
|
||||||
|
r = await new Promise(function (done) {
|
||||||
|
var t = setInterval(async function () {
|
||||||
|
waited += 4;
|
||||||
|
var g = await api("align_script", { email: email, project_id: pid });
|
||||||
|
if (g.ok && !g.pending) { clearInterval(t); done(g); return; }
|
||||||
|
if (waited > 240) { clearInterval(t); done({ ok: false, error: "That is taking unusually long." }); }
|
||||||
|
}, 4000);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
b.disabled = false; b.textContent = "Cut it to the clock";
|
||||||
|
if (!r.ok) { showMsg("msg", r.error || "Could not measure that."); return; }
|
||||||
|
if (r.note) { showMsg("msg", r.note); return; }
|
||||||
|
paint(r);
|
||||||
|
showMsg("msg", "Shots re-cut at real word endings.", "ok");
|
||||||
|
load();
|
||||||
|
};
|
||||||
|
|
||||||
|
api("align_script", { email: email, project_id: pid }).then(function (r) {
|
||||||
|
if (r && r.ok && !r.pending && r.audio) paint(r);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function bindPreviz() {
|
||||||
|
var b = document.getElementById("pzmake");
|
||||||
|
if (!b) return;
|
||||||
|
var note = document.getElementById("pznote");
|
||||||
|
|
||||||
|
async function poll() {
|
||||||
|
var waited = 0;
|
||||||
|
return await new Promise(function (done) {
|
||||||
|
var t = setInterval(async function () {
|
||||||
|
waited += 4;
|
||||||
|
var g = await api("make_previz", { email: email, project_id: pid });
|
||||||
|
if (g.ok && !g.pending) { clearInterval(t); done(g); return; }
|
||||||
|
if (g.ok && g.pending && note) note.textContent = g.status_text || "";
|
||||||
|
if (waited > 240) { clearInterval(t); done({ ok: false, error: "That is taking unusually long." }); }
|
||||||
|
}, 4000);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
b.onclick = async function () {
|
||||||
|
hideMsg("msg");
|
||||||
|
b.disabled = true; b.textContent = "Speaking…";
|
||||||
|
var r = await api("make_previz", { email: email, project_id: pid });
|
||||||
|
if (r.ok && r.pending) { note.textContent = r.status_text || ""; r = await poll(); }
|
||||||
|
b.disabled = false; b.textContent = "Speak it again";
|
||||||
|
if (!r.ok) { note.textContent = ""; showMsg("msg", r.error || "Could not speak that."); return; }
|
||||||
|
note.textContent = r.status_text || "";
|
||||||
|
pzPaint(r.lines || []);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Already spoken? Show it without asking again.
|
||||||
|
api("make_previz", { email: email, project_id: pid }).then(function (r) {
|
||||||
|
if (r && r.ok && !r.pending && (r.lines || []).length) {
|
||||||
|
b.textContent = "Speak it again";
|
||||||
|
note.textContent = r.status_text || "";
|
||||||
|
pzPaint(r.lines);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// The picture is the hook; the link carries the video. Never the video itself
|
||||||
|
// over MMS - carriers transcode it into mush.
|
||||||
|
function bindShare() {
|
||||||
|
var b = document.getElementById("sharebtn");
|
||||||
|
if (!b) return;
|
||||||
|
var note = document.getElementById("sharenote"),
|
||||||
|
out = document.getElementById("shareout");
|
||||||
|
|
||||||
|
// The file URL ends in /public with no filename. The headers are already
|
||||||
|
// correct (video/mp4, filename=final.mp4) so anything that reads them is
|
||||||
|
// fine, but clients that sniff the extension from the URL string are not.
|
||||||
|
// A filename query is accepted and ignored by the file service.
|
||||||
|
// Filled in by share_link, which owns the address. A link straight to the
|
||||||
|
// file would be invisible to us; this one is counted server side.
|
||||||
|
var SHARE_LINK = "";
|
||||||
|
function named(url) { return SHARE_LINK || ""; }
|
||||||
|
|
||||||
|
function paint(r) {
|
||||||
|
var kb = Math.round((r.bytes || 0) / 1024);
|
||||||
|
var link = named(r.video || "");
|
||||||
|
var msg = ((DATA && DATA.script && DATA.script.title)
|
||||||
|
? DATA.script.title + " — " : "")
|
||||||
|
+ ((DATA && DATA.project && DATA.project.pet_name) || "your pet")
|
||||||
|
+ " has something to say. " + link;
|
||||||
|
out.innerHTML = '<div style="display:flex;gap:18px;flex-wrap:wrap;align-items:flex-start">'
|
||||||
|
+ '<img src="' + esc(r.image) + '" alt="share picture" '
|
||||||
|
+ 'style="width:190px;border-radius:10px;border:1px solid var(--line);display:block">'
|
||||||
|
+ '<div style="flex:1 1 260px">'
|
||||||
|
+ '<p class="foot" style="margin:0 0 10px">' + esc(r.size || "") + ' · ' + kb + ' KB'
|
||||||
|
+ ' · well inside the 600KB most carriers allow, so it will not be '
|
||||||
|
+ 'downsampled.</p>'
|
||||||
|
+ '<label class="mini">The message</label>'
|
||||||
|
+ '<textarea id="sharemsg" style="min-height:70px">' + esc(msg) + '</textarea>'
|
||||||
|
+ '<button type="button" class="btn" id="sharelink" style="margin-top:8px">Share the video</button>'
|
||||||
|
+ '<button type="button" class="btn ghost" id="sharecopy" style="margin-left:8px;margin-top:8px">Copy the message</button>'
|
||||||
|
+ '<a class="btn ghost" style="margin-left:8px;display:inline-block;text-decoration:none" '
|
||||||
|
+ 'href="' + esc(r.image) + '" download>Download the picture</a>'
|
||||||
|
+ '<p class="foot" style="margin:12px 0 0;word-break:break-all">' + esc(link)
|
||||||
|
+ '<span id="viewcount"></span></p>'
|
||||||
|
+ '</div></div>';
|
||||||
|
api("share_link", { email: email, project_id: pid }).then(function (s) {
|
||||||
|
if (!(s && s.ok)) return;
|
||||||
|
SHARE_LINK = s.url || "";
|
||||||
|
var el = document.getElementById("viewcount");
|
||||||
|
if (el) {
|
||||||
|
el.innerHTML = '<br>' + esc(SHARE_LINK) + '<br>Opened ' + (s.views || 0)
|
||||||
|
+ ' time' + ((s.views === 1) ? '' : 's') + '.';
|
||||||
|
}
|
||||||
|
var t = document.getElementById("sharemsg");
|
||||||
|
if (t && SHARE_LINK) t.value = t.value.replace(/https?:\/\/\S+/, SHARE_LINK);
|
||||||
|
});
|
||||||
|
var sl = document.getElementById("sharelink");
|
||||||
|
if (sl) sl.onclick = async function () {
|
||||||
|
var title = (DATA && DATA.script && DATA.script.title) || "A video";
|
||||||
<!--PTLCHUNK-->
|
<!--PTLCHUNK-->
|
||||||
Loading…
Reference in a new issue