From e0db55e0dbf45584b120c9dba7b2355090060144 Mon Sep 17 00:00:00 2001 From: gator Date: Wed, 9 Sep 2026 01:08:09 +0000 Subject: [PATCH] Share the video, with a link that ends in .mp4 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- script.html | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/script.html b/script.html index 648a605..64546d5 100644 --- a/script.html +++ b/script.html @@ -1136,9 +1136,22 @@ function bindShare() { 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. + 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) { 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) ? DATA.script.title + " — " : "") + ((DATA && DATA.project && DATA.project.pet_name) || "your pet") @@ -1152,10 +1165,26 @@ function bindShare() { + 'downsampled.

' + '' + '' - + '' + + '' + + '' + 'Download the picture' + + '

' + esc(link) + '

' + ''; + 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"); if (c) c.onclick = function () { var t = document.getElementById("sharemsg");