Resolve external embed previews and keep their real MIME types

This commit is contained in:
Fisto
2026-09-16 12:52:44 +02:00
parent 7fa6118b6f
commit 1b5fcfed2f
11 changed files with 313 additions and 41 deletions
+34 -20
View File
@@ -392,24 +392,38 @@
return el(className ?? "figcaption", "vk-media-banner", parts.join(" · "));
}
/** Grid thumbnail source: cached preview, then the local file, then the original link. */
/**
* Grid thumbnail source: cached preview, then the local file.
* Attachment URLs are direct files; embed URLs are pages, never rendered as media.
*/
function gridSource(item) {
return item.thumbUrl || item.localUrl || item.url;
if (item.thumbUrl) return item.thumbUrl;
if (item.localUrl) return item.localUrl;
if (item.source !== "embed") return item.url;
return null;
}
function placeholder(media, item) {
media.replaceChildren(el("span", "vk-media-card-kind", item.kind.toUpperCase()));
}
function playIcon(item) {
const play = el("span", "vk-media-play", "▶");
play.title = "Play";
play.addEventListener("click", event => {
event.stopPropagation();
openViewer(item, true);
});
return play;
}
function renderCard(item) {
const figure = el("figure", "vk-media-figure");
const media = el("div", "vk-media-media");
const source = gridSource(item);
const visual = item.kind === "image" || item.kind === "gif" || item.kind === "video";
const playable = /\.(mp4|webm|m4v)(\?|$)/i.test(item.url ?? "");
if (visual && /^(https?:|\/)/.test(source) && item.kind !== "video") {
const img = document.createElement("img");
img.loading = "lazy";
img.src = source;
img.alt = item.kind;
media.append(img);
} else if (item.kind === "video" && /^(https?:|\/)/.test(source)) {
if (item.kind === "video" && source && item.source !== "embed" && playable) {
// Discord has no server-side video thumbnails; the browser shows the first frame.
const video = document.createElement("video");
video.preload = "metadata";
@@ -423,20 +437,20 @@
},
{ once: true }
);
video.addEventListener("error", () => placeholder(media, item), { once: true });
media.append(video);
} else if (source && /^(https?:|\/)/.test(source)) {
const img = document.createElement("img");
img.loading = "lazy";
img.src = source;
img.alt = item.kind;
img.addEventListener("error", () => placeholder(media, item), { once: true });
media.append(img);
} else {
media.append(el("span", "vk-media-card-kind", item.kind.toUpperCase()));
placeholder(media, item);
}
if (item.kind === "video") {
const play = el("span", "vk-media-play", "▶");
play.title = "Play";
play.addEventListener("click", event => {
event.stopPropagation();
openViewer(item, true);
});
media.append(play);
}
if (item.kind === "video") media.append(playIcon(item));
media.addEventListener("click", () => openViewer(item, false));
figure.append(media);