Skip to content

Commit

Permalink
reduce /node-api/media-type calls, when some nft media have the same …
Browse files Browse the repository at this point in the history
…urls (#1191)

Fixes #1180
  • Loading branch information
tom2drum authored Sep 19, 2023
1 parent c18c5c9 commit c389dc7
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 39 deletions.
41 changes: 2 additions & 39 deletions ui/shared/nft/NftMedia.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,11 @@ import { AspectRatio, chakra, Skeleton, useColorModeValue } from '@chakra-ui/rea
import React from 'react';
import { useInView } from 'react-intersection-observer';

import type { StaticRoute } from 'nextjs-routes';
import { route } from 'nextjs-routes';

import useFetch from 'lib/hooks/useFetch';

import NftFallback from './NftFallback';
import NftHtml from './NftHtml';
import NftImage from './NftImage';
import NftVideo from './NftVideo';
import type { MediaType } from './utils';
import { getPreliminaryMediaType } from './utils';
import useNftMediaType from './useNftMediaType';

interface Props {
url: string | null;
Expand All @@ -21,44 +15,13 @@ interface Props {
}

const NftMedia = ({ url, className, isLoading }: Props) => {
const [ type, setType ] = React.useState<MediaType | undefined>();
const [ isMediaLoading, setIsMediaLoading ] = React.useState(Boolean(url));
const [ isLoadingError, setIsLoadingError ] = React.useState(false);

const bgColor = useColorModeValue('blackAlpha.50', 'whiteAlpha.50');

const fetch = useFetch();
const { ref, inView } = useInView({ triggerOnce: true });

React.useEffect(() => {
if (!url || isLoading || !inView) {
return;
}

// media could be either image, gif or video
// so we pre-fetch the resources in order to get its content type
// have to do it via Node.js due to strict CSP for connect-src
// but in order not to abuse our server firstly we check file url extension
// and if it is valid we will trust it and display corresponding media component

const preliminaryType = getPreliminaryMediaType(url);

if (preliminaryType) {
setType(preliminaryType);
return;
}

const mediaTypeResourceUrl = route({ pathname: '/node-api/media-type' as StaticRoute<'/api/media-type'>['pathname'], query: { url } });
fetch(mediaTypeResourceUrl)
.then((_data) => {
const data = _data as { type: MediaType | undefined };
setType(data.type || 'image');
})
.catch(() => {
setType('image');
});

}, [ url, isLoading, fetch, inView ]);
const type = useNftMediaType(url, !isLoading && inView);

const handleMediaLoaded = React.useCallback(() => {
setIsMediaLoading(false);
Expand Down
50 changes: 50 additions & 0 deletions ui/shared/nft/useNftMediaType.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { useQuery } from '@tanstack/react-query';

import type { StaticRoute } from 'nextjs-routes';
import { route } from 'nextjs-routes';

import type { ResourceError } from 'lib/api/resources';
import useFetch from 'lib/hooks/useFetch';

import type { MediaType } from './utils';
import { getPreliminaryMediaType } from './utils';

export default function useNftMediaType(url: string | null, isEnabled: boolean) {

const fetch = useFetch();

const { data } = useQuery<unknown, ResourceError<unknown>, MediaType>(
[ 'nft-media-type', url ],
async() => {
if (!url) {
return 'image';
}

// media could be either image, gif, video or html-page
// so we pre-fetch the resources in order to get its content type
// have to do it via Node.js due to strict CSP for connect-src
// but in order not to abuse our server firstly we check file url extension
// and if it is valid we will trust it and display corresponding media component

const preliminaryType = getPreliminaryMediaType(url);

if (preliminaryType) {
return preliminaryType;
}

try {
const mediaTypeResourceUrl = route({ pathname: '/node-api/media-type' as StaticRoute<'/api/media-type'>['pathname'], query: { url } });
const response = await fetch<{ type: MediaType | undefined }, ResourceError>(mediaTypeResourceUrl);

return 'type' in response ? response.type ?? 'image' : 'image';
} catch (error) {
return 'image';
}
},
{
enabled: isEnabled && Boolean(url),
staleTime: Infinity,
});

return data;
}

0 comments on commit c389dc7

Please sign in to comment.