Files
marco/app/modifiers/cached-image.js

65 lines
1.7 KiB
JavaScript

import { modifier } from 'ember-modifier';
const CACHE_NAME = 'nostr-image-cache-v1';
export default modifier((element, [url]) => {
let objectUrl = null;
async function loadImage() {
if (!url) {
element.src = '';
return;
}
try {
const cache = await caches.open(CACHE_NAME);
const cachedResponse = await cache.match(url);
if (cachedResponse) {
const blob = await cachedResponse.blob();
objectUrl = URL.createObjectURL(blob);
element.src = objectUrl;
return;
}
// Not in cache, try to fetch it
// eslint-disable-next-line warp-drive/no-external-request-patterns
const response = await fetch(url, {
mode: 'cors', // Required to read the blob for caching
credentials: 'omit',
});
if (response.ok) {
// Clone the response before reading the blob because a response stream can only be read once
const cacheResponse = response.clone();
await cache.put(url, cacheResponse);
const blob = await response.blob();
objectUrl = URL.createObjectURL(blob);
element.src = objectUrl;
} else {
// Fetch failed (e.g. 404), fallback to standard browser loading
element.src = url;
}
} catch (error) {
// CORS errors or network failures will land here.
// Fallback to letting the browser handle it directly.
console.warn(
`Failed to cache image ${url}, falling back to standard src`,
error
);
element.src = url;
}
}
loadImage();
// Cleanup: revoke the object URL when the element is destroyed or the URL changes
return () => {
if (objectUrl) {
URL.revokeObjectURL(objectUrl);
objectUrl = null;
}
};
});