Share the video, with a link that ends in .mp4

The file URL ends in /public with no filename, which is fine for anything that
reads headers — it already serves Content-Type video/mp4 and a
Content-Disposition of final.mp4 — but clients that sniff the extension out of
the URL string get it wrong. A filename query is accepted and ignored by the
file service, so the link can end in .mp4 at a cost of a dozen characters.

The button uses the native share sheet where there is one, which on a phone is
the shortest path into a text message, and falls back to copying.
This commit is contained in:
gator 2026-09-09 01:08:09 +00:00
parent b94b0557c2
commit e0db55e0db

View file

@ -1136,9 +1136,22 @@ function bindShare() {
var note = document.getElementById("sharenote"), var note = document.getElementById("sharenote"),
out = document.getElementById("shareout"); 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.
function named(url) {
if (!url) return "";
var pet = ((DATA && DATA.project && DATA.project.pet_name) || "video");
var t = ((DATA && DATA.script && DATA.script.title) || "");
var slug = (pet + " " + t).toLowerCase().replace(/[^a-z0-9]+/g, "-")
.replace(/^-|-$/g, "").slice(0, 40) || "video";
return url + (url.indexOf("?") < 0 ? "?" : "&") + "v=" + slug + ".mp4";
}
function paint(r) { function paint(r) {
var kb = Math.round((r.bytes || 0) / 1024); var kb = Math.round((r.bytes || 0) / 1024);
var link = r.video || ""; var link = named(r.video || "");
var msg = ((DATA && DATA.script && DATA.script.title) var msg = ((DATA && DATA.script && DATA.script.title)
? DATA.script.title + " — " : "") ? DATA.script.title + " — " : "")
+ ((DATA && DATA.project && DATA.project.pet_name) || "your pet") + ((DATA && DATA.project && DATA.project.pet_name) || "your pet")
@ -1152,10 +1165,26 @@ function bindShare() {
+ 'downsampled.</p>' + 'downsampled.</p>'
+ '<label class="mini">The message</label>' + '<label class="mini">The message</label>'
+ '<textarea id="sharemsg" style="min-height:70px">' + esc(msg) + '</textarea>' + '<textarea id="sharemsg" style="min-height:70px">' + esc(msg) + '</textarea>'
+ '<button type="button" class="btn ghost" id="sharecopy" style="margin-top:8px">Copy the message</button>' + '<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" ' + '<a class="btn ghost" style="margin-left:8px;display:inline-block;text-decoration:none" '
+ 'href="' + esc(r.image) + '" download>Download the picture</a>' + 'href="' + esc(r.image) + '" download>Download the picture</a>'
+ '<p class="foot" style="margin:12px 0 0;word-break:break-all">' + esc(link) + '</p>'
+ '</div></div>'; + '</div></div>';
var sl = document.getElementById("sharelink");
if (sl) sl.onclick = async function () {
var title = (DATA && DATA.script && DATA.script.title) || "A video";
// The native sheet is the shortest path into a text message on a phone.
if (navigator.share) {
try { await navigator.share({ title: title, text: msg, url: link }); return; }
catch (e) { if (e && e.name === "AbortError") return; }
}
try {
await navigator.clipboard.writeText(link);
sl.textContent = "Link copied";
setTimeout(function () { sl.textContent = "Share the video"; }, 1600);
} catch (e) { showMsg("msg", "Copy this: " + link); }
};
var c = document.getElementById("sharecopy"); var c = document.getElementById("sharecopy");
if (c) c.onclick = function () { if (c) c.onclick = function () {
var t = document.getElementById("sharemsg"); var t = document.getElementById("sharemsg");