refactor thumbnail fetching, add caching

This commit is contained in:
Tom (plebeius.eth)
2024-10-13 12:58:29 +02:00
parent deead474a5
commit 7e8eb83bf6
4 changed files with 54 additions and 23 deletions
+9 -5
View File
@@ -1,4 +1,4 @@
import { useEffect, useMemo, useRef, useState } from 'react'; import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { createPortal } from 'react-dom'; import { createPortal } from 'react-dom';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { Link, useLocation, useParams } from 'react-router-dom'; import { Link, useLocation, useParams } from 'react-router-dom';
@@ -119,14 +119,18 @@ const CatalogPost = ({ post }: { post: Comment }) => {
const initialCommentMediaInfo = useMemo(() => getCommentMediaInfo(post), [post]); const initialCommentMediaInfo = useMemo(() => getCommentMediaInfo(post), [post]);
const [commentMediaInfo, setCommentMediaInfo] = useState(initialCommentMediaInfo); const [commentMediaInfo, setCommentMediaInfo] = useState(initialCommentMediaInfo);
const hasThumbnail = getHasThumbnail(commentMediaInfo, link); const hasThumbnail = getHasThumbnail(commentMediaInfo, link);
useEffect(() => {
const fetchThumbnail = useCallback(async () => {
if (initialCommentMediaInfo?.type === 'webpage' && !initialCommentMediaInfo.thumbnail) { if (initialCommentMediaInfo?.type === 'webpage' && !initialCommentMediaInfo.thumbnail) {
fetchWebpageThumbnailIfNeeded(initialCommentMediaInfo).then(setCommentMediaInfo); const newMediaInfo = await fetchWebpageThumbnailIfNeeded(initialCommentMediaInfo);
} else { setCommentMediaInfo(newMediaInfo);
setCommentMediaInfo(initialCommentMediaInfo);
} }
}, [initialCommentMediaInfo]); }, [initialCommentMediaInfo]);
useEffect(() => {
fetchThumbnail();
}, [fetchThumbnail]);
const { hidden } = useHide({ cid }); const { hidden } = useHide({ cid });
const location = useLocation(); const location = useLocation();
+9 -5
View File
@@ -1,4 +1,4 @@
import { useEffect, useMemo, useState } from 'react'; import { useCallback, useEffect, useMemo, useState } from 'react';
import { Trans, useTranslation } from 'react-i18next'; import { Trans, useTranslation } from 'react-i18next';
import { Link, useLocation, useParams } from 'react-router-dom'; import { Link, useLocation, useParams } from 'react-router-dom';
import { Comment, useAuthorAvatar, useComment, useEditedComment, useSubplebbit } from '@plebbit/plebbit-react-hooks'; import { Comment, useAuthorAvatar, useComment, useEditedComment, useSubplebbit } from '@plebbit/plebbit-react-hooks';
@@ -212,14 +212,18 @@ const PostMedia = ({ post }: PostProps) => {
// some sites have CORS access, so the thumbnail can be fetched client-side, which is helpful if subplebbit.settings.fetchThumbnailUrls is false // some sites have CORS access, so the thumbnail can be fetched client-side, which is helpful if subplebbit.settings.fetchThumbnailUrls is false
const initialCommentMediaInfo = useMemo(() => getCommentMediaInfo(post), [post]); const initialCommentMediaInfo = useMemo(() => getCommentMediaInfo(post), [post]);
const [commentMediaInfo, setCommentMediaInfo] = useState(initialCommentMediaInfo); const [commentMediaInfo, setCommentMediaInfo] = useState(initialCommentMediaInfo);
useEffect(() => {
const fetchThumbnail = useCallback(async () => {
if (initialCommentMediaInfo?.type === 'webpage' && !initialCommentMediaInfo.thumbnail) { if (initialCommentMediaInfo?.type === 'webpage' && !initialCommentMediaInfo.thumbnail) {
fetchWebpageThumbnailIfNeeded(initialCommentMediaInfo).then(setCommentMediaInfo); const newMediaInfo = await fetchWebpageThumbnailIfNeeded(initialCommentMediaInfo);
} else { setCommentMediaInfo(newMediaInfo);
setCommentMediaInfo(initialCommentMediaInfo);
} }
}, [initialCommentMediaInfo]); }, [initialCommentMediaInfo]);
useEffect(() => {
fetchThumbnail();
}, [fetchThumbnail]);
const { url } = commentMediaInfo || {}; const { url } = commentMediaInfo || {};
let type = commentMediaInfo?.type; let type = commentMediaInfo?.type;
const gifFrameUrl = useFetchGifFirstFrame(url); const gifFrameUrl = useFetchGifFirstFrame(url);
+9 -5
View File
@@ -1,4 +1,4 @@
import { useEffect, useMemo, useState } from 'react'; import { useCallback, useEffect, useMemo, useState } from 'react';
import { Trans, useTranslation } from 'react-i18next'; import { Trans, useTranslation } from 'react-i18next';
import { Link, useLocation, useParams } from 'react-router-dom'; import { Link, useLocation, useParams } from 'react-router-dom';
import { Comment, useAuthorAvatar, useComment, useEditedComment, useSubplebbit } from '@plebbit/plebbit-react-hooks'; import { Comment, useAuthorAvatar, useComment, useEditedComment, useSubplebbit } from '@plebbit/plebbit-react-hooks';
@@ -43,14 +43,18 @@ const PostInfoAndMedia = ({ openReplyModal, post, postReplyCount = 0, roles }: P
// some sites have CORS access, so the thumbnail can be fetched client-side, which is helpful if subplebbit.settings.fetchThumbnailUrls is false // some sites have CORS access, so the thumbnail can be fetched client-side, which is helpful if subplebbit.settings.fetchThumbnailUrls is false
const initialCommentMediaInfo = useMemo(() => getCommentMediaInfo(post), [post]); const initialCommentMediaInfo = useMemo(() => getCommentMediaInfo(post), [post]);
const [commentMediaInfo, setCommentMediaInfo] = useState(initialCommentMediaInfo); const [commentMediaInfo, setCommentMediaInfo] = useState(initialCommentMediaInfo);
useEffect(() => {
const fetchThumbnail = useCallback(async () => {
if (initialCommentMediaInfo?.type === 'webpage' && !initialCommentMediaInfo.thumbnail) { if (initialCommentMediaInfo?.type === 'webpage' && !initialCommentMediaInfo.thumbnail) {
fetchWebpageThumbnailIfNeeded(initialCommentMediaInfo).then(setCommentMediaInfo); const newMediaInfo = await fetchWebpageThumbnailIfNeeded(initialCommentMediaInfo);
} else { setCommentMediaInfo(newMediaInfo);
setCommentMediaInfo(initialCommentMediaInfo);
} }
}, [initialCommentMediaInfo]); }, [initialCommentMediaInfo]);
useEffect(() => {
fetchThumbnail();
}, [fetchThumbnail]);
const hasThumbnail = getHasThumbnail(commentMediaInfo, link); const hasThumbnail = getHasThumbnail(commentMediaInfo, link);
const [showThumbnail, setShowThumbnail] = useState(true); const [showThumbnail, setShowThumbnail] = useState(true);
+27 -8
View File
@@ -135,14 +135,6 @@ const fetchWebpageThumbnail = async (url: string): Promise<string | undefined> =
} }
}; };
export const fetchWebpageThumbnailIfNeeded = async (commentMediaInfo: CommentMediaInfo): Promise<CommentMediaInfo> => {
if (commentMediaInfo.type === 'webpage' && !commentMediaInfo.thumbnail) {
const thumbnail = await fetchWebpageThumbnail(commentMediaInfo.url);
return { ...commentMediaInfo, thumbnail };
}
return commentMediaInfo;
};
export const getCommentMediaInfo = (comment: Comment): CommentMediaInfo | undefined => { export const getCommentMediaInfo = (comment: Comment): CommentMediaInfo | undefined => {
if (!comment?.thumbnailUrl && !comment?.link) { if (!comment?.thumbnailUrl && !comment?.link) {
return; return;
@@ -192,3 +184,30 @@ export const getMediaDimensions = (commentMediaInfo: CommentMediaInfo | undefine
return ''; return '';
}; };
export const fetchWebpageThumbnailIfNeeded = async (commentMediaInfo: CommentMediaInfo): Promise<CommentMediaInfo> => {
if (commentMediaInfo.type === 'webpage' && !commentMediaInfo.thumbnail) {
const cachedThumbnail = getCachedThumbnail(commentMediaInfo.url);
if (cachedThumbnail) {
return { ...commentMediaInfo, thumbnail: cachedThumbnail };
}
const thumbnail = await fetchWebpageThumbnail(commentMediaInfo.url);
if (thumbnail) {
setCachedThumbnail(commentMediaInfo.url, thumbnail);
}
return { ...commentMediaInfo, thumbnail };
}
return commentMediaInfo;
};
const THUMBNAIL_CACHE_KEY = 'webpageThumbnailCache';
export const getCachedThumbnail = (url: string): string | null => {
const cache = JSON.parse(localStorage.getItem(THUMBNAIL_CACHE_KEY) || '{}');
return cache[url] || null;
};
export const setCachedThumbnail = (url: string, thumbnail: string): void => {
const cache = JSON.parse(localStorage.getItem(THUMBNAIL_CACHE_KEY) || '{}');
cache[url] = thumbnail;
localStorage.setItem(THUMBNAIL_CACHE_KEY, JSON.stringify(cache));
};