Thumbnails shouldn't be revoked

So make the face crops behave the same too
This commit is contained in:
Manav Rathi
2024-09-27 17:02:51 +05:30
parent 4bb6aa2b39
commit 370d4af008
4 changed files with 44 additions and 37 deletions

View File

@@ -64,34 +64,19 @@ export const ItemCard: React.FC<React.PropsWithChildren<ItemCardProps>> = ({
if (!coverFile) return;
let didCancel = false;
let thisObjectURL: string | undefined;
const go = async () => {
if (coverFaceID) {
const blob = await faceCrop(coverFaceID, coverFile);
if (!didCancel) {
thisObjectURL = blob
? URL.createObjectURL(blob)
: undefined;
setCoverImageURL(thisObjectURL);
}
} else {
const url = await downloadManager.getThumbnailForPreview(
coverFile,
isScrolling,
);
if (!didCancel) {
thisObjectURL = url;
setCoverImageURL(thisObjectURL);
}
}
};
void go();
if (coverFaceID) {
void faceCrop(coverFaceID, coverFile).then(
(url) => !didCancel && setCoverImageURL(url),
);
} else {
void downloadManager
.getThumbnailForPreview(coverFile, isScrolling)
.then((url) => !didCancel && setCoverImageURL(url));
}
return () => {
didCancel = true;
if (thisObjectURL) URL.revokeObjectURL(thisObjectURL);
};
}, [coverFile, coverFaceID, isScrolling]);

View File

@@ -216,25 +216,22 @@ const FaceCropImageView: React.FC<FaceCropImageViewProps> = ({
enteFile,
placeholderDimension,
}) => {
const [objectURL, setObjectURL] = useState<string | undefined>();
const [url, setURL] = useState<string | undefined>();
useEffect(() => {
let didCancel = false;
let thisObjectURL: string | undefined;
void faceCrop(faceID, enteFile).then((blob) => {
if (blob && !didCancel)
setObjectURL((thisObjectURL = URL.createObjectURL(blob)));
});
void faceCrop(faceID, enteFile).then(
(url) => !didCancel && setURL(url),
);
return () => {
didCancel = true;
if (thisObjectURL) URL.revokeObjectURL(thisObjectURL);
};
}, [faceID, enteFile]);
return objectURL ? (
<img style={{ objectFit: "cover" }} src={objectURL} />
return url ? (
<img style={{ objectFit: "cover" }} src={url} />
) : (
<Skeleton
variant="circular"

View File

@@ -145,7 +145,7 @@ class DownloadManagerImpl {
}
/**
* Resolves with an object URL that points to the file's thumbnail.
* Resolves with an URL that points to the file's thumbnail.
*
* The thumbnail will be downloaded (unless {@link localOnly} is true) and
* cached.
@@ -155,6 +155,9 @@ class DownloadManagerImpl {
* to download the file but should instead fulfill the request from the
* cache. This avoids an unbounded flurry of requests on scroll, only
* downloading when the position has quiescized.
*
* The returned URL is actually an object URL, but it should not be revoked
* since the download manager caches it for future use.
*/
async getThumbnailForPreview(
file: EnteFile,

View File

@@ -95,6 +95,13 @@ class MLState {
* whose faces we are regenerating.
*/
inFlightFaceCropRegens = new Map<number, Promise<void>>();
/**
* Cached object URLs to face crops that we have previously vended out.
*
* The cache is only cleared on logout.
*/
faceCropObjectURLCache = new Map<string, string>();
}
/** State shared by the functions in this module. See {@link MLState}. */
@@ -187,6 +194,9 @@ export const logoutML = async () => {
// execution contexts], it gets called first in the logout sequence, and
// then this function (`logoutML`) gets called at a later point in time.
[..._state.faceCropObjectURLCache.values()].forEach((url) =>
URL.revokeObjectURL(url),
);
_state = new MLState();
await clearMLDB();
};
@@ -646,7 +656,10 @@ export const getAnnotatedFacesForFile = async (
};
/**
* Return the cached face crop for the given face, regenerating it if needed.
* Return a URL to the face crop for the given face, regenerating it if needed.
*
* The resultant URL is cached (both the object URL itself, and the underlying
* file crop blob used to generete it).
*
* @param faceID The id of the face whose face crop we want.
*
@@ -662,8 +675,17 @@ export const faceCrop = async (faceID: string, enteFile: EnteFile) => {
await inFlight;
const cache = await blobCache("face-crops");
return cache.get(faceID);
let url = _state.faceCropObjectURLCache.get(faceID);
if (!url) {
const cache = await blobCache("face-crops");
const blob = await cache.get(faceID);
if (blob) {
url = URL.createObjectURL(blob);
if (url) _state.faceCropObjectURLCache.set(faceID, url);
}
}
return url;
};
/**