From 73420242d095de4ce352a108206bbc1989dffe99 Mon Sep 17 00:00:00 2001 From: Jared Vititoe Date: Sat, 23 May 2026 22:01:45 -0400 Subject: [PATCH] fix: fallback to legacy media URL on 401, fix EC avatar letter centering downloadMedia: on 401 (SW session race or allow_redirect hop stripping auth), retry via /_matrix/media/v3/ which is public on this homeserver (allow_public_access_to_media_repo: true). Fixes images not loading after sending, and avatar 401s in call prescreen tiles. CallEmbed: inject flex-centering CSS for EC 0.19.4 participant avatar container so the initial letter is correctly centered in its circle. CSS class names are scoped to _avatarContainer_1mrho_40 in EC 0.19.4. Co-Authored-By: Claude Sonnet 4.6 --- src/app/plugins/call/CallEmbed.ts | 3 +++ src/app/utils/matrix.ts | 20 +++++++++++++++++--- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/app/plugins/call/CallEmbed.ts b/src/app/plugins/call/CallEmbed.ts index 68064974e..8c6b37999 100644 --- a/src/app/plugins/call/CallEmbed.ts +++ b/src/app/plugins/call/CallEmbed.ts @@ -321,6 +321,9 @@ export class CallEmbed { 'html, body { background: none !important; }', `:root { color-scheme: ${this.themeKind}; }`, '[style*="height: 0"][style*="z-index: 1"][style*="align-self: center"] { display: none !important; }', + // EC 0.19.4: avatar uses line-height centering which breaks in some tile sizes; + // override with flexbox for reliable centering of the initial letter. + '._avatarContainer_1mrho_40 ._avatar_va14e_8 { display: flex !important; align-items: center !important; justify-content: center !important; line-height: 1 !important; }', ].join('\n'); } diff --git a/src/app/utils/matrix.ts b/src/app/utils/matrix.ts index 6cc26ae02..dd6ab8fc1 100644 --- a/src/app/utils/matrix.ts +++ b/src/app/utils/matrix.ts @@ -299,9 +299,23 @@ export const mxcUrlToHttp = ( export const downloadMedia = async (src: string): Promise => { // this request is authenticated by service worker const res = await fetch(src, { method: 'GET' }); - if (!res.ok) throw new Error(`Media download failed: ${res.status} ${res.statusText}`); - const blob = await res.blob(); - return blob; + if (res.ok) return res.blob(); + + // On 401 fall back to the legacy unauthenticated media path. + // This covers the race where the SW session isn't set yet, or when matrix-js-sdk + // appends ?allow_redirect=true and Synapse strips auth on the redirect hop. + // Requires allow_public_access_to_media_repo: true on the homeserver. + if (res.status === 401) { + const legacyUrl = src + .replace('/_matrix/client/v1/media/download/', '/_matrix/media/v3/download/') + .replace('/_matrix/client/v1/media/thumbnail/', '/_matrix/media/v3/thumbnail/'); + if (legacyUrl !== src) { + const legacyRes = await fetch(legacyUrl, { method: 'GET' }); + if (legacyRes.ok) return legacyRes.blob(); + } + } + + throw new Error(`Media download failed: ${res.status} ${res.statusText}`); }; export const downloadEncryptedMedia = async (