From 7a33b3198a66c17081ef817758841a77f860b6db Mon Sep 17 00:00:00 2001 From: Hampus Date: Mon, 24 Aug 2026 12:56:26 +0200 Subject: [PATCH] fix(app): stop reprobing image format support on every build (#1976) --- .../features/voice/utils/MediaCapabilities.ts | 104 +----------------- 1 file changed, 5 insertions(+), 99 deletions(-) diff --git a/fluxer_app/src/features/voice/utils/MediaCapabilities.ts b/fluxer_app/src/features/voice/utils/MediaCapabilities.ts index 6668cf195..90cd21d42 100644 --- a/fluxer_app/src/features/voice/utils/MediaCapabilities.ts +++ b/fluxer_app/src/features/voice/utils/MediaCapabilities.ts @@ -1,16 +1,11 @@ // SPDX-License-Identifier: AGPL-3.0-or-later -import Config from '@app/features/app/config/Config'; import {isSvgMimeType, normalizeImageMimeType} from '@app/features/expressions/utils/ImageUploadFileUtils'; import AppStorage from '@app/features/platform/state/PersistentStorage'; -import {useEffect, useState, useSyncExternalStore} from 'react'; -export type MediaFormat = 'avif' | 'webp' | 'apng' | 'jxl'; - -export interface CapabilityResult { +interface CapabilityResult { avif: boolean; webp: boolean; - apng: boolean; jxl: boolean; probedAt: number; uaKey: string; @@ -19,16 +14,12 @@ export interface CapabilityResult { const AVIF_PROBE = 'data:image/avif;base64,AAAAIGZ0eXBhdmlmAAAAAGF2aWZtaWYxbWlhZk1BMUIAAADybWV0YQAAAAAAAAAoaGRscgAAAAAAAAAAcGljdAAAAAAAAAAAAAAAAGxpYmF2aWYAAAAADnBpdG0AAAAAAAEAAAAeaWxvYwAAAABEAAABAAEAAAABAAABGgAAAB0AAAAoaWluZgAAAAAAAQAAABppbmZlAgAAAAABAABhdjAxQ29sb3IAAAAAamlwcnAAAABLaXBjbwAAABRpc3BlAAAAAAAAAAEAAAABAAAAEHBpeGkAAAAAAwgICAAAAAxhdjFDgQAMAAAAABNjb2xybmNseAACAAIABoAAAAAXaXBtYQAAAAAAAAABAAEEAQKDBAAAACVtZGF0EgAKCBgIYAQQUDAJEBQYJlAQUAAAAB1FmDuOmIs='; const WEBP_PROBE = 'data:image/webp;base64,UklGRhwAAABXRUJQVlA4TBAAAAAvAAAAAAfQ//73v/+BiOh/AAA='; -const APNG_PROBE = - 'data:image/apng;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAACGFjVEwAAAABAAAAALOZWzgAAAANSURBVAjXY/j//z8DAAj8Av6IXwbgAAAAAElFTkSuQmCC'; const JXL_PROBE = 'data:image/jxl;base64,/wr6PwH4TWFvLnVMkM4='; const STORAGE_KEY = 'fluxer:media_caps:v1'; const PROBE_TIMEOUT_MS = 1500; function buildUaKey(): string { - const ua = typeof navigator !== 'undefined' ? navigator.userAgent : 'ssr'; - const version = Config.PUBLIC_BUILD_VERSION ?? 'dev'; - return `${version}:${ua}`; + return typeof navigator !== 'undefined' ? navigator.userAgent : 'ssr'; } function isRecord(value: unknown): value is Record { @@ -67,7 +58,6 @@ function readCached(): CapabilityResult | null { return { avif: parsed.avif === true, webp: parsed.webp === true, - apng: parsed.apng === true, jxl: parsed.jxl === true, probedAt: typeof parsed.probedAt === 'number' ? parsed.probedAt : 0, uaKey: parsed.uaKey, @@ -86,28 +76,16 @@ function writeCached(result: CapabilityResult): void { let cached: CapabilityResult | null = null; let inflight: Promise | null = null; -const listeners = new Set<() => void>(); - -function notify(): void { - for (const fn of listeners) fn(); -} - async function runProbes(): Promise { - const [avif, webp, apng, jxl] = await Promise.all([ - probeOne(AVIF_PROBE), - probeOne(WEBP_PROBE), - probeOne(APNG_PROBE), - probeOne(JXL_PROBE), - ]); - return {avif, webp, apng, jxl, probedAt: Date.now(), uaKey: buildUaKey()}; + const [avif, webp, jxl] = await Promise.all([probeOne(AVIF_PROBE), probeOne(WEBP_PROBE), probeOne(JXL_PROBE)]); + return {avif, webp, jxl, probedAt: Date.now(), uaKey: buildUaKey()}; } -export async function probeMediaCapabilities(): Promise { +async function probeMediaCapabilities(): Promise { if (cached) return cached; const fromStorage = readCached(); if (fromStorage) { cached = fromStorage; - notify(); return fromStorage; } if (inflight) return inflight; @@ -115,65 +93,12 @@ export async function probeMediaCapabilities(): Promise { const result = await runProbes(); cached = result; writeCached(result); - notify(); inflight = null; return result; })(); return inflight; } -export function getMediaCapabilitiesSync(): CapabilityResult | null { - if (cached) return cached; - cached = readCached(); - return cached; -} - -type CroppableAssetKind = 'avatar' | 'guild_icon' | 'banner' | 'splash' | 'embed_splash' | 'emoji' | 'sticker'; - -function pickAnimated(kind: CroppableAssetKind, caps: CapabilityResult): MediaFormat | null { - switch (kind) { - case 'emoji': - case 'sticker': - case 'avatar': - case 'guild_icon': - case 'banner': - case 'splash': - case 'embed_splash': - if (caps.webp) return 'webp'; - if (caps.apng) return 'apng'; - return null; - } -} - -function pickStatic(kind: CroppableAssetKind, caps: CapabilityResult): MediaFormat | null { - switch (kind) { - case 'avatar': - case 'guild_icon': - case 'banner': - case 'splash': - case 'embed_splash': - if (caps.avif) return 'avif'; - if (caps.webp) return 'webp'; - return null; - case 'emoji': - case 'sticker': - if (caps.webp) return 'webp'; - if (caps.avif) return 'avif'; - return null; - } -} - -export const MediaCapabilities = { - probe: probeMediaCapabilities, - getSync: getMediaCapabilitiesSync, - bestFormatFor(kind: CroppableAssetKind, animated: boolean): MediaFormat | null { - const caps = getMediaCapabilitiesSync(); - if (!caps) return null; - return animated ? pickAnimated(kind, caps) : pickStatic(kind, caps); - }, - canCropFormat, -}; - export async function canCropFormat(mime: string): Promise { const m = normalizeImageMimeType(mime); if (m === 'image/png' || m === 'image/apng' || m === 'image/jpeg' || m === 'image/gif') { @@ -203,22 +128,3 @@ async function canDecodeViaImage(mime: string): Promise { return false; } } - -export function useCapabilityHint(): CapabilityResult | null { - const subscribe = (cb: () => void): (() => void) => { - listeners.add(cb); - return () => { - listeners.delete(cb); - }; - }; - const getSnapshot = (): CapabilityResult | null => cached; - const getServerSnapshot = (): CapabilityResult | null => null; - const value = useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot); - const [bootstrapped, setBootstrapped] = useState(value); - useEffect(() => { - if (!bootstrapped) { - void probeMediaCapabilities().then((r) => setBootstrapped(r)); - } - }, [bootstrapped]); - return value ?? bootstrapped; -}