Files
cinny/src/app/hooks/useAuthenticatedMediaUrl.ts
litruv c286501be8 Improve timeline scroll, media layout, avatars, and emoji coverage.
Remember room scroll position across switches, reserve image/video heights from Matrix dimensions, cache authenticated media blobs for avatars, restore jumbo emoji-only messages, and extend emoji font unicode-range for Unicode 15 glyphs.
2026-07-22 20:00:14 +10:00

80 lines
2.2 KiB
TypeScript

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<string | undefined>(() => {
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<string> => {
try {
return await resolveAuthenticatedMediaUrl(src, useAuthentication);
} catch (error) {
console.warn('[useAuthenticatedMediaFetch] Error fetching authenticated media:', error);
return src;
}
},
[mx]
);
};