import { useCallback, useEffect, useState } from 'react'; import { useMatrixClient } from './useMatrixClient'; import { getCachedAuthenticatedMediaUrl, isAuthenticatedMediaUrl, resolveAuthenticatedMediaUrl, } from '../utils/authenticatedMediaCache'; /** * Resolves media URLs for Matrix authenticated media. * Uses a shared blob-URL cache so avatars/thumbs are not re-fetched on every remount. */ export const useAuthenticatedMediaUrl = ( src: string | undefined, useAuthentication: boolean ): string | undefined => { const mx = useMatrixClient(); const [blobUrl, setBlobUrl] = useState(() => { if (!src) return undefined; if (!useAuthentication || !isAuthenticatedMediaUrl(src)) return src; return getCachedAuthenticatedMediaUrl(src); }); useEffect(() => { if (!src) { setBlobUrl(undefined); return undefined; } if (!useAuthentication || !isAuthenticatedMediaUrl(src)) { setBlobUrl(src); return undefined; } const cached = getCachedAuthenticatedMediaUrl(src); if (cached) { setBlobUrl(cached); return undefined; } let cancelled = false; resolveAuthenticatedMediaUrl(src, useAuthentication) .then((url) => { if (!cancelled) setBlobUrl(url); }) .catch((error) => { console.warn('[useAuthenticatedMediaUrl] Error fetching authenticated media:', error); if (!cancelled) setBlobUrl(src); }); return () => { cancelled = true; // Shared cache owns blob URLs — do not revoke on unmount. }; }, [src, useAuthentication, mx]); return blobUrl; }; /** * Creates an authenticated fetch function for media URLs. * Useful for components that need to load multiple images. */ export const useAuthenticatedMediaFetch = () => { const mx = useMatrixClient(); return useCallback( async (src: string, useAuthentication = true): Promise => { try { return await resolveAuthenticatedMediaUrl(src, useAuthentication); } catch (error) { console.warn('[useAuthenticatedMediaFetch] Error fetching authenticated media:', error); return src; } }, [mx] ); };