fix(watch): a link whose video is being made again says so, in the page's language
The public watch route answers video_preparing for an asset that is pending or downloading, and the page shows "being prepared — try again" with a Retry instead of "this link is gone". watch.html ships one lang; the page now sets documentElement.lang to the language its strings were picked in.
This commit is contained in:
@@ -76,13 +76,20 @@ function displayUrl(url: string): string {
|
||||
}
|
||||
}
|
||||
|
||||
/** What a 404 from the link means: `video_preparing` is a link whose video is being made again (a
|
||||
* re-download, a conversion) and will work shortly; any other is a link that is gone. */
|
||||
async function notFoundState(r: Response): Promise<"preparing" | "gone"> {
|
||||
const body = (await r.json().catch(() => null)) as { detail?: { reason?: string } } | null;
|
||||
return body?.detail?.reason === "video_preparing" ? "preparing" : "gone";
|
||||
}
|
||||
|
||||
export default function WatchPage() {
|
||||
const token = window.location.pathname.split("/watch/")[1]?.split(/[/?#]/)[0] ?? "";
|
||||
// Seeded from the URL rather than corrected by the effect below: with no token there is nothing
|
||||
// to load, and "loading" was committed and painted before the effect said so.
|
||||
const [status, setStatus] = useState<"loading" | "ready" | "password" | "gone" | "error">(
|
||||
token ? "loading" : "gone",
|
||||
);
|
||||
const [status, setStatus] = useState<
|
||||
"loading" | "ready" | "password" | "gone" | "preparing" | "error"
|
||||
>(token ? "loading" : "gone");
|
||||
const [meta, setMeta] = useState<Meta | null>(null);
|
||||
const [password, setPassword] = useState("");
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
@@ -110,16 +117,16 @@ export default function WatchPage() {
|
||||
useEffect(() => {
|
||||
if (!token) return; // the seed above already says "gone"
|
||||
send(`/api/public/watch/${encodeURIComponent(token)}`)
|
||||
.then((r) => {
|
||||
// Only a 404 says the link is gone (unknown, expired, revoked, or its file removed). Anything
|
||||
// else — a 5xx while the server restarts, a dropped connection — is a failure worth retrying,
|
||||
// not a dead link.
|
||||
if (r.status === 404) return null;
|
||||
.then((r): Promise<Meta | "preparing" | "gone"> => {
|
||||
// Only a 404 says the link is gone (unknown, expired, revoked, or its file removed) — or that
|
||||
// its video is being made again (`notFoundState`). Anything else — a 5xx while the server
|
||||
// restarts, a dropped connection — is a failure worth retrying, not a dead link.
|
||||
if (r.status === 404) return notFoundState(r);
|
||||
if (!r.ok) throw new Error(`HTTP ${r.status}`);
|
||||
return r.json() as Promise<Meta>;
|
||||
})
|
||||
.then((m) => {
|
||||
if (!m) setStatus("gone");
|
||||
if (typeof m === "string") setStatus(m);
|
||||
else if (m.needs_password) setStatus("password");
|
||||
else {
|
||||
setMeta(m);
|
||||
@@ -151,7 +158,7 @@ export default function WatchPage() {
|
||||
return;
|
||||
}
|
||||
if (r.status === 404) {
|
||||
setStatus("gone");
|
||||
setStatus(await notFoundState(r));
|
||||
return;
|
||||
}
|
||||
if (!r.ok) throw new Error(`HTTP ${r.status}`);
|
||||
@@ -194,6 +201,19 @@ export default function WatchPage() {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{status === "preparing" && (
|
||||
<div className="flex-1 grid place-items-center text-center">
|
||||
{/* Announced like the failure below: it replaces the loading line. */}
|
||||
<div role="status">
|
||||
<div className="text-lg font-semibold">{T.preparing}</div>
|
||||
<div className="text-sm text-muted mt-1">{T.preparingHint}</div>
|
||||
<Button variant="primary" size="md" onClick={retry} className="mt-4">
|
||||
{T.retry}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{status === "error" && (
|
||||
<div className="flex-1 grid place-items-center text-center">
|
||||
{/* Announced: it replaces the loading line, and this page has no live region of its own. */}
|
||||
|
||||
Reference in New Issue
Block a user