mirror of
https://github.com/bitsocialnet/5chan.git
synced 2026-08-03 07:41:04 +02:00
refactor thumbnail fetching, add caching
This commit is contained in:
@@ -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();
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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));
|
||||||
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user