This commit is contained in:
+76
-9
@@ -86,6 +86,8 @@ const hlsInstances = new WeakMap();
|
||||
const debugEntries = [];
|
||||
const summaryTranslationCache = new Map();
|
||||
const summaryTranslationInflight = new Map();
|
||||
const resultPreviewCache = new Map();
|
||||
const resultPreviewInflight = new Map();
|
||||
let cardSummaryObserver = null;
|
||||
const PREVIEW_PLACEHOLDER = "https://placehold.co/1280x720/0a0a0a/ffffff?text=Preview";
|
||||
|
||||
@@ -96,6 +98,25 @@ function proxiedPreviewURL(src) {
|
||||
return `/api/preview/stream?url=${encodeURIComponent(src)}`;
|
||||
}
|
||||
|
||||
function transcodedPreviewURL(src) {
|
||||
if (!src) {
|
||||
return "";
|
||||
}
|
||||
return `/api/preview/transcode?url=${encodeURIComponent(src)}`;
|
||||
}
|
||||
|
||||
function buildPlayablePreviewURL(src, source = "") {
|
||||
const trimmed = String(src || "").trim();
|
||||
if (!trimmed) {
|
||||
return "";
|
||||
}
|
||||
const lower = trimmed.toLowerCase();
|
||||
if (lower.includes(".m3u8") && (String(source || "").toLowerCase() === "artgrid" || lower.includes("artgrid") || lower.includes("artlist"))) {
|
||||
return transcodedPreviewURL(trimmed);
|
||||
}
|
||||
return proxiedPreviewURL(trimmed);
|
||||
}
|
||||
|
||||
function isLowValueThumbnailURL(src) {
|
||||
const lower = String(src || "").toLowerCase();
|
||||
if (!lower) {
|
||||
@@ -471,7 +492,7 @@ function showResultModalVideo(src) {
|
||||
if (!src) {
|
||||
return;
|
||||
}
|
||||
attachVideoSource(resultModalVideo, proxiedPreviewURL(src));
|
||||
attachVideoSource(resultModalVideo, src);
|
||||
setHidden(resultModalVideo, false, "");
|
||||
}
|
||||
|
||||
@@ -555,6 +576,37 @@ async function translateCardSummary(node) {
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchResultPreview(item) {
|
||||
const key = String(item?.link || "").trim();
|
||||
if (!key) {
|
||||
return null;
|
||||
}
|
||||
if (resultPreviewCache.has(key)) {
|
||||
return resultPreviewCache.get(key);
|
||||
}
|
||||
if (resultPreviewInflight.has(key)) {
|
||||
return resultPreviewInflight.get(key);
|
||||
}
|
||||
const request = (async () => {
|
||||
try {
|
||||
const preview = await api("/api/download/preview", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ url: key }),
|
||||
});
|
||||
resultPreviewCache.set(key, preview);
|
||||
return preview;
|
||||
} catch (error) {
|
||||
logEvent("result:preview:fetch_failed", { link: key, source: item?.source || "", message: error.message });
|
||||
return null;
|
||||
} finally {
|
||||
resultPreviewInflight.delete(key);
|
||||
}
|
||||
})();
|
||||
resultPreviewInflight.set(key, request);
|
||||
return request;
|
||||
}
|
||||
|
||||
function ensureCardSummaryObserver() {
|
||||
if (cardSummaryObserver || typeof IntersectionObserver === "undefined") {
|
||||
return;
|
||||
@@ -618,12 +670,20 @@ function renderResults(results) {
|
||||
node.dataset.summaryTranslated = "false";
|
||||
node.addEventListener("click", () => openResultModal(item));
|
||||
previewVideo.poster = usableThumbnail ? item.thumbnailUrl : "";
|
||||
if (item.previewVideoUrl) {
|
||||
const mediaArea = node.querySelector(".relative");
|
||||
mediaArea.addEventListener("mouseenter", () => {
|
||||
logEvent("preview:hover:start", { title: item.title, source: item.source, previewVideoUrl: item.previewVideoUrl });
|
||||
const mediaArea = node.querySelector(".relative");
|
||||
if (item.previewVideoUrl || item.source === "Google Video") {
|
||||
mediaArea.addEventListener("mouseenter", async () => {
|
||||
let previewURL = item.previewVideoUrl || "";
|
||||
if (!previewURL && item.source === "Google Video") {
|
||||
const preview = await fetchResultPreview(item);
|
||||
previewURL = preview?.previewStreamUrl || "";
|
||||
}
|
||||
logEvent("preview:hover:start", { title: item.title, source: item.source, previewVideoUrl: previewURL });
|
||||
if (!previewURL) {
|
||||
return;
|
||||
}
|
||||
overlays.forEach((overlay) => overlay.classList.add("hidden"));
|
||||
startHoverPreview(previewVideo, proxiedPreviewURL(item.previewVideoUrl));
|
||||
startHoverPreview(previewVideo, buildPlayablePreviewURL(previewURL, item.source));
|
||||
});
|
||||
mediaArea.addEventListener("mouseleave", () => {
|
||||
logEvent("preview:hover:end", { title: item.title, source: item.source });
|
||||
@@ -666,7 +726,7 @@ async function prepareDirectDownload(targetUrl) {
|
||||
downloadResult.textContent = "preview loaded";
|
||||
}
|
||||
|
||||
function openResultModal(item) {
|
||||
async function openResultModal(item) {
|
||||
if (!resultModalReady) {
|
||||
logEvent("result:modal:error", { message: "result modal is not fully initialized" });
|
||||
return;
|
||||
@@ -688,7 +748,14 @@ function openResultModal(item) {
|
||||
resetResultModalMedia();
|
||||
const embedURL = buildResultModalEmbedURL(item);
|
||||
const fallbackReason = item.previewBlockedReason || "Embedded view was unavailable, switched to fallback preview.";
|
||||
if (item.source === "Google Video" && item.mediaMode === "thumbnail") {
|
||||
let resolvedPreviewURL = item.previewVideoUrl || "";
|
||||
if (!resolvedPreviewURL && item.source === "Google Video") {
|
||||
const preview = await fetchResultPreview(item);
|
||||
resolvedPreviewURL = preview?.previewStreamUrl || "";
|
||||
}
|
||||
if (resolvedPreviewURL) {
|
||||
showResultModalVideo(buildPlayablePreviewURL(resolvedPreviewURL, item.source));
|
||||
} else if (item.source === "Google Video" && item.mediaMode === "thumbnail") {
|
||||
showResultModalGooglePanel(item, item.snippet || "Open source page or download directly.");
|
||||
} else if (item.mediaMode === "embed" && embedURL && embedURL !== "about:blank") {
|
||||
showResultModalFrame(embedURL);
|
||||
@@ -703,7 +770,7 @@ function openResultModal(item) {
|
||||
window.clearTimeout(timeout);
|
||||
};
|
||||
} else if (item.mediaMode === "preview_video" && item.previewVideoUrl) {
|
||||
showResultModalVideo(item.previewVideoUrl);
|
||||
showResultModalVideo(buildPlayablePreviewURL(item.previewVideoUrl, item.source));
|
||||
} else if (item.mediaMode === "thumbnail" && hasUsableThumbnail(item.thumbnailUrl)) {
|
||||
showResultModalThumbnail(item.thumbnailUrl, item.title || "");
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user