Add daemon restart, preview diagnostics, browse caching, and rate-limit pauses

This commit is contained in:
Fisto
2026-09-17 07:33:35 +02:00
parent cba7ae8143
commit dea1724eb3
13 changed files with 367 additions and 56 deletions
+14 -45
View File
@@ -443,13 +443,6 @@
media.replaceChildren(node);
}
/** Only real video files can be framed; embed pages (YouTube etc.) never are. */
function canFrameVideo(item) {
const direct = /\.(mp4|webm|m4v)(\?|$)/i;
if (item.playUrl && direct.test(item.playUrl)) return true;
return item.source !== "embed" && direct.test(item.url ?? "");
}
function playIcon(item) {
const play = el("span", "vk-media-play", "▶");
play.title = "Play";
@@ -472,11 +465,8 @@
const media = el("div", "vk-media-media");
const imageSource = item.localUrl || item.thumbUrl;
const fallbackSource = item.source !== "embed" ? item.url : null;
const streamPath = `/api/media/${item.scrapeId}/${item.itemId}/stream`;
const animatedGif =
item.kind === "gif" && item.remotePreviewUrl && /\.gif(\?|$)/i.test(item.remotePreviewUrl)
? item.remotePreviewUrl
: null;
// Hover plays the cached animated GIF from the archive, never the provider.
const animatedGif = item.kind === "gif" && item.animUrl ? item.animUrl : null;
if (imageSource) {
const img = document.createElement("img");
@@ -496,23 +486,6 @@
}
media.append(img);
} else if (item.kind === "video" && canFrameVideo(item)) {
// No thumbnail: take the first frame through the same-origin stream endpoint,
// which refreshes expired URLs and avoids cross-origin blocking.
const video = document.createElement("video");
video.preload = "metadata";
video.muted = true;
video.playsInline = true;
video.src = streamPath;
video.addEventListener(
"loadedmetadata",
() => {
if (video.duration) video.currentTime = Math.min(0.1, video.duration / 2);
},
{ once: true }
);
video.addEventListener("error", () => placeholder(media, item), { once: true });
media.append(video);
} else if (fallbackSource && /^(https?:|\/)/.test(fallbackSource)) {
const img = document.createElement("img");
img.loading = "lazy";
@@ -1231,22 +1204,6 @@
{ once: true }
);
media.append(video);
} else if (item.kind === "video" && canFrameVideo(item)) {
// No still available: show the first frame through the stream endpoint.
const video = document.createElement("video");
video.preload = "metadata";
video.muted = true;
video.playsInline = true;
video.src = streamUrl;
video.addEventListener(
"loadedmetadata",
() => {
if (video.duration) video.currentTime = Math.min(0.1, video.duration / 2);
},
{ once: true }
);
media.append(video);
media.append(viewerPlayIcon(item));
} else if ((item.kind === "image" || item.kind === "gif") && /^(https?:|\/)/.test(source)) {
const img = document.createElement("img");
img.src = source;
@@ -1254,6 +1211,7 @@
media.append(img);
} else {
media.append(el("span", "vk-media-card-kind", item.kind.toUpperCase()));
if (item.kind === "video") media.append(viewerPlayIcon(item));
}
meta.replaceChildren();
@@ -1490,6 +1448,17 @@
document.querySelector("#media-clean")?.addEventListener("click", openCleanModal);
document.querySelector("#daemon-restart")?.addEventListener("click", async () => {
if (!window.confirm("Restart the daemon? The page will disconnect for a few seconds.")) return;
try {
await window.VK.api.post("/api/daemon/restart", {});
} catch {
// The daemon exits mid-response on purpose.
}
setStatus("daemon restarting; reload the page in a few seconds");
});
window.addEventListener("resize", () => {
if (state.view) layoutTop();
});