Improved icon fetching with DriveCache disabled
Some checks failed
Run Integration Tests / test (push) Failing after 37s
Some checks failed
Run Integration Tests / test (push) Failing after 37s
This commit is contained in:
parent
43d7068c7a
commit
b17b9bc05f
6 changed files with 239 additions and 131 deletions
|
@ -34,19 +34,19 @@
|
|||
}
|
||||
|
||||
// Handle image/favicon loading errors
|
||||
function handleImageError(imgElement, retryCount = 8, retryDelay = 500) {
|
||||
function handleImageError(imgElement, retryCount = 10, retryDelay = 200) {
|
||||
const isFavicon = !!imgElement.closest('.favicon-wrapper');
|
||||
const container = imgElement.closest(type === 'image' ? '.image' : '.result_item');
|
||||
const titleSelector = type === 'image' ? '.img_title' : '.result-url';
|
||||
const title = container?.querySelector(titleSelector);
|
||||
const fullURL = imgElement.getAttribute('data-full');
|
||||
|
||||
if (retryCount > 0 && !imgElement.dataset.checked404) {
|
||||
imgElement.dataset.checked404 = '1'; // avoid infinite loop
|
||||
if (retryCount > 0 && !imgElement.dataset.checked410) {
|
||||
imgElement.dataset.checked410 = '1'; // avoid infinite loop
|
||||
|
||||
fetch(fullURL, { method: 'HEAD' })
|
||||
.then(res => {
|
||||
if (res.status === 404) {
|
||||
if (res.status === 410) {
|
||||
fallbackToGlobe(imgElement);
|
||||
} else {
|
||||
setTimeout(() => {
|
||||
|
@ -61,26 +61,32 @@
|
|||
} else {
|
||||
fallbackToGlobe(imgElement);
|
||||
}
|
||||
}
|
||||
|
||||
function fallbackToGlobe(imgElement) {
|
||||
imgElement.closest('.favicon-wrapper')?.classList.remove('loading');
|
||||
if (title) title.classList.remove('title-loading');
|
||||
function fallbackToGlobe(imgElement) {
|
||||
const type = document.getElementById('template-data').getAttribute('data-type');
|
||||
const isFavicon = !!imgElement.closest('.favicon-wrapper');
|
||||
const container = imgElement.closest(type === 'image' ? '.image' : '.result_item');
|
||||
const titleSelector = type === 'image' ? '.img_title' : '.result-url';
|
||||
const title = container?.querySelector(titleSelector);
|
||||
|
||||
if (isFavicon) {
|
||||
const wrapper = imgElement.closest('.favicon-wrapper') || imgElement.parentElement;
|
||||
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
||||
svg.setAttribute("xmlns", "http://www.w3.org/2000/svg");
|
||||
svg.setAttribute("viewBox", "0 -960 960 960");
|
||||
svg.setAttribute("height", imgElement.height || "16");
|
||||
svg.setAttribute("width", imgElement.width || "16");
|
||||
svg.setAttribute("fill", "currentColor");
|
||||
svg.classList.add("favicon", "globe-fallback");
|
||||
imgElement.closest('.favicon-wrapper')?.classList.remove('loading');
|
||||
if (title) title.classList.remove('title-loading');
|
||||
|
||||
if (isFavicon) {
|
||||
const wrapper = imgElement.closest('.favicon-wrapper') || imgElement.parentElement;
|
||||
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
||||
svg.setAttribute("xmlns", "http://www.w3.org/2000/svg");
|
||||
svg.setAttribute("viewBox", "0 -960 960 960");
|
||||
svg.setAttribute("height", imgElement.height || "16");
|
||||
svg.setAttribute("width", imgElement.width || "16");
|
||||
svg.setAttribute("fill", "currentColor");
|
||||
svg.classList.add("favicon", "globe-fallback");
|
||||
svg.innerHTML = `<path d="M480-80q-82 0-155-31.5t-127.5-86Q143-252 111.5-325T80-480q0-83 31.5-155.5t86-127Q252-817 325-848.5T480-880q83 0 155.5 31.5t127 86q54.5 54.5 86 127T880-480q0 82-31.5 155t-86 127.5q-54.5 54.5-127 86T480-80Zm0-82q26-36 45-75t31-83H404q12 44 31 83t45 75Zm-104-16q-18-33-31.5-68.5T322-320H204q29 50 72.5 87t99.5 55Zm208 0q56-18 99.5-55t72.5-87H638q-9 38-22.5 73.5T584-178ZM170-400h136q-3-20-4.5-39.5T300-480q0-21 1.5-40.5T306-560H170q-5 20-7.5 39.5T160-480q0 21 2.5 40.5T170-400Zm216 0h188q3-20 4.5-39.5T580-480q0-21-1.5-40.5T574-560H386q-3 20-4.5 39.5T380-480q0 21 1.5 40.5T386-400Zm268 0h136q5-20 7.5-39.5T800-480q0-21-2.5-40.5T790-560H654q3 20 4.5 39.5T660-480q0 21-1.5 40.5T654-400Zm-16-240h118q-29-50-72.5-87T584-782q18 33 31.5 68.5T638-640Zm-234 0h152q-12-44-31-83t-45-75q-26 36-45 75t-31 83Zm-200 0h118q9-38 22.5-73.5T376-782q-56 18-99.5 55T204-640Z"/>`;
|
||||
imgElement.remove();
|
||||
wrapper.appendChild(svg);
|
||||
} else if (type === 'image') {
|
||||
container?.remove();
|
||||
}
|
||||
imgElement.remove();
|
||||
wrapper.appendChild(svg);
|
||||
} else if (type === 'image') {
|
||||
container?.remove();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -113,7 +119,7 @@
|
|||
function registerMediaElement(imgElement) {
|
||||
const id = imgElement.getAttribute('data-id');
|
||||
if (!id) return;
|
||||
|
||||
|
||||
let wrapper = imgElement.closest('.favicon-wrapper');
|
||||
if (!wrapper) {
|
||||
wrapper = document.createElement('span');
|
||||
|
@ -121,24 +127,86 @@
|
|||
imgElement.replaceWith(wrapper);
|
||||
wrapper.appendChild(imgElement);
|
||||
}
|
||||
|
||||
|
||||
addLoadingEffects(imgElement);
|
||||
|
||||
if (hardCacheEnabled) {
|
||||
imgElement.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=';
|
||||
imgElement.onerror = () => handleImageError(imgElement, 3, 1000);
|
||||
} else {
|
||||
imgElement.src = imgElement.getAttribute('data-full');
|
||||
imgElement.onload = () => removeLoadingEffects(imgElement);
|
||||
imgElement.onerror = () => handleImageError(imgElement, 3, 1000);
|
||||
}
|
||||
|
||||
// Track it
|
||||
if (!mediaMap.has(id)) {
|
||||
mediaMap.set(id, []);
|
||||
}
|
||||
|
||||
const tryLoadImage = (attempts = 25, delay = 300) => {
|
||||
fetch(`/image_status?image_ids=${id}`)
|
||||
.then(res => res.json())
|
||||
.then(map => {
|
||||
const url = map[id];
|
||||
if (!url) {
|
||||
if (attempts > 0) {
|
||||
// Exponential backoff with jitter
|
||||
const nextDelay = Math.min(delay * 2 + Math.random() * 100, 5000);
|
||||
setTimeout(() => tryLoadImage(attempts - 1, nextDelay), nextDelay);
|
||||
} else {
|
||||
fallbackToGlobe(imgElement);
|
||||
}
|
||||
} else if (url.endsWith('globe.svg') || url.endsWith('missing.svg')) {
|
||||
fallbackToGlobe(imgElement);
|
||||
} else {
|
||||
// Remove cache buster to leverage browser caching
|
||||
const newImg = imgElement.cloneNode();
|
||||
newImg.src = url;
|
||||
newImg.onload = () => removeLoadingEffects(newImg);
|
||||
// Add retry mechanism for final load
|
||||
newImg.onerror = () => handleImageError(newImg, 3, 500);
|
||||
imgElement.parentNode.replaceChild(newImg, imgElement);
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
if (attempts > 0) {
|
||||
const nextDelay = Math.min(delay * 2, 5000);
|
||||
setTimeout(() => tryLoadImage(attempts - 1, nextDelay), nextDelay);
|
||||
} else {
|
||||
fallbackToGlobe(imgElement);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// Initial load attempt with retry handler
|
||||
imgElement.src = imgElement.getAttribute('data-full');
|
||||
imgElement.onload = () => removeLoadingEffects(imgElement);
|
||||
// Start polling immediately instead of waiting for error
|
||||
setTimeout(() => tryLoadImage(), 500); // Start polling after initial load attempt
|
||||
|
||||
// Store reference in tracking map
|
||||
if (!mediaMap.has(id)) mediaMap.set(id, []);
|
||||
mediaMap.get(id).push(imgElement);
|
||||
}
|
||||
}
|
||||
|
||||
function pollFaviconUntilReady(imgElement, id, retries = 8, delay = 700) {
|
||||
let attempts = 0;
|
||||
function poll() {
|
||||
fetch(`/image_status?image_ids=${id}`)
|
||||
.then(res => res.json())
|
||||
.then(map => {
|
||||
const url = map[id];
|
||||
if (url && !url.endsWith('globe.svg') && !url.endsWith('missing.svg')) {
|
||||
|
||||
const newImg = imgElement.cloneNode();
|
||||
newImg.src = url + "?v=" + Date.now();
|
||||
newImg.onload = () => removeLoadingEffects(newImg);
|
||||
newImg.onerror = () => fallbackToGlobe(newImg);
|
||||
imgElement.parentNode.replaceChild(newImg, imgElement);
|
||||
} else if (attempts < retries) {
|
||||
attempts++;
|
||||
setTimeout(poll, delay);
|
||||
} else {
|
||||
fallbackToGlobe(imgElement);
|
||||
}
|
||||
}).catch(() => {
|
||||
if (attempts < retries) {
|
||||
attempts++;
|
||||
setTimeout(poll, delay);
|
||||
} else {
|
||||
fallbackToGlobe(imgElement);
|
||||
}
|
||||
});
|
||||
}
|
||||
poll();
|
||||
}
|
||||
|
||||
// Check status of all tracked media elements
|
||||
function checkMediaStatus() {
|
||||
|
@ -182,9 +250,10 @@
|
|||
}
|
||||
}
|
||||
|
||||
mediaMap.clear();
|
||||
for (const [id, imgs] of stillPending) {
|
||||
mediaMap.set(id, imgs);
|
||||
for (const id of Array.from(mediaMap.keys())) {
|
||||
if (!stillPending.has(id)) {
|
||||
mediaMap.delete(id);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue