Fall back to other instances when a channel avatar fails #1

Merged
salix merged 2 commits from avatar-instance-fallback into main 2026-09-29 20:16:37 +02:00
Owner

Channel avatars, most visibly in channel search results, often stayed as letter placeholders. An avatar URL names whichever instance served the page, and it was the only URL ever tried, so a flaky or since-removed instance meant no avatar. Video thumbnails already fell back across instances; avatars did not.

Changes

  • invio-core: new avatar_urls(configured, url), exported over UniFFI like thumbnail_urls. It returns the original URL, then the same /ggpht/... image on each configured instance in failover order (yt3.ggpht.com for Direct YouTube). It also handles raw YouTube image-CDN URLs and the https,http://... form.
  • invio-core: cache_channel_avatar and the feed-sync avatar prefetch try those candidates in order. cache_channel_avatar now takes the instance list; Adwaita is its only caller.
  • invio-core: the image cache no longer stores responses that are not image bytes, so an HTML error or challenge page can't be cached as .jpg, shadow the real avatar, and stop the failover.
  • invio-adwaita: channel avatars pass the configured instances through; comment avatars fail over the same way through fetch_first.
  • invio-android: new AvatarImage composable steps through avatarUrls candidates on load error, with the instances from a LocalInstanceBaseUrls provided in AppRoot. Used for channel avatars in search, channel pages, subscriptions, Shorts, the watch page and TV browse, and for comment avatars.

Testing

  • cargo test in invio-core: 578 passed, including 2 new avatar_urls tests.
  • cargo check passes for invio-server and invio-adwaita.
  • Android: :app:compileDebugKotlin passes against freshly generated bindings; InvidiousInstancesTest (8 tests, including a new avatarUrls test against the real core) passes.
  • Live probe: an avatar URL on a dead host fails without fallback and downloads the real JPEG through a configured instance with it.
  • Not rerun in the desktop app or on an Android device after the change.

Not covered

macOS loads avatar URLs directly and doesn't use this fallback yet.

Channel avatars, most visibly in channel search results, often stayed as letter placeholders. An avatar URL names whichever instance served the page, and it was the only URL ever tried, so a flaky or since-removed instance meant no avatar. Video thumbnails already fell back across instances; avatars did not. ## Changes - **invio-core**: new `avatar_urls(configured, url)`, exported over UniFFI like `thumbnail_urls`. It returns the original URL, then the same `/ggpht/...` image on each configured instance in failover order (`yt3.ggpht.com` for Direct YouTube). It also handles raw YouTube image-CDN URLs and the `https,http://...` form. - **invio-core**: `cache_channel_avatar` and the feed-sync avatar prefetch try those candidates in order. `cache_channel_avatar` now takes the instance list; Adwaita is its only caller. - **invio-core**: the image cache no longer stores responses that are not image bytes, so an HTML error or challenge page can't be cached as `.jpg`, shadow the real avatar, and stop the failover. - **invio-adwaita**: channel avatars pass the configured instances through; comment avatars fail over the same way through `fetch_first`. - **invio-android**: new `AvatarImage` composable steps through `avatarUrls` candidates on load error, with the instances from a `LocalInstanceBaseUrls` provided in `AppRoot`. Used for channel avatars in search, channel pages, subscriptions, Shorts, the watch page and TV browse, and for comment avatars. ## Testing - `cargo test` in invio-core: 578 passed, including 2 new `avatar_urls` tests. - `cargo check` passes for invio-server and invio-adwaita. - Android: `:app:compileDebugKotlin` passes against freshly generated bindings; `InvidiousInstancesTest` (8 tests, including a new `avatarUrls` test against the real core) passes. - Live probe: an avatar URL on a dead host fails without fallback and downloads the real JPEG through a configured instance with it. - Not rerun in the desktop app or on an Android device after the change. ## Not covered macOS loads avatar URLs directly and doesn't use this fallback yet.
fall back to other instances when a channel avatar fails
All checks were successful
Build x86_64 Flatpak / flatpak (pull_request) Successful in 3m33s
4bb802252a
An avatar URL names whichever instance served the page, and it was the
only URL ever tried. A flaky or since-removed instance left the avatar as
a letter placeholder, most visibly in channel search results.

Add avatar_urls(), which lists the original URL and then the same /ggpht
image through each configured instance in failover order. The core avatar
cache (used by Adwaita and the feed-sync prefetch) walks those candidates,
and Adwaita comment avatars fail over the same way.

The cache also refuses to store responses that are not image bytes, so an
HTML error or challenge page can no longer be written as a .jpg, shadow
the real avatar, and stop the failover.
android: fall back to other instances for avatars through the core
Some checks failed
Build x86_64 Flatpak / flatpak (pull_request) Has been cancelled
75a2b69c25
Export avatar_urls over UniFFI and add an AvatarImage composable that
steps through its candidates on load error, the same way thumbnails
already fail over. The configured instances come from a
LocalInstanceBaseUrls provided in AppRoot.

Channel avatars in search, channel pages, subscriptions, Shorts, the
watch page and TV browse now use it, as do comment avatars.
salix merged commit a6266cf69c into main 2026-09-29 20:16:37 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
salix/invio!1
No description provided.