fix(avatars): use proper getThumbnailUrl API to eliminate 404 errors

Root cause: Widgets were using getUserAvatar() which returns bare
filenames like 'user-default.png'. These were being used directly as
image src URLs, causing 404 errors like /user-default.png.

Solution: Use getAvatarUrl() dependency which calls getThumbnailUrl()
to convert filenames to proper URLs like /thumbnail?type=persona&file=...

Changes:
- userInfoWidget.js: Use getAvatarUrl('persona', rawAvatar) instead of
  raw avatar validation
- sillytavern.js: Simplify updatePersonaAvatar() to trust
  getSafeThumbnailUrl() which already calls getThumbnailUrl()

This eliminates 404 errors on initial render and when switching tabs.
This commit is contained in:
Lucas 'Paperboy' Rose-Winters
2025-10-24 00:26:51 +11:00
parent f0f04297f7
commit eb4ac57dae
2 changed files with 36 additions and 21 deletions
@@ -26,6 +26,7 @@ export function registerUserInfoWidget(registry, dependencies) {
const { const {
getContext, getContext,
getUserAvatar, getUserAvatar,
getAvatarUrl,
getFallbackAvatar, getFallbackAvatar,
getExtensionSettings, getExtensionSettings,
onStatsChange onStatsChange
@@ -50,7 +51,16 @@ export function registerUserInfoWidget(registry, dependencies) {
const settings = getExtensionSettings(); const settings = getExtensionSettings();
const context = getContext(); const context = getContext();
const userName = context.name1; const userName = context.name1;
const userPortrait = getUserAvatar() || getFallbackAvatar();
// Get user avatar - use getAvatarUrl to convert filename to proper thumbnail URL
let userPortrait = getFallbackAvatar();
const rawAvatar = getUserAvatar();
// Convert raw avatar filename to proper thumbnail URL
// getAvatarUrl calls getThumbnailUrl which generates URLs like /thumbnail?type=persona&file=...
if (rawAvatar) {
userPortrait = getAvatarUrl('persona', rawAvatar);
}
// Merge default config // Merge default config
const finalConfig = { const finalConfig = {
+25 -20
View File
@@ -16,7 +16,8 @@ import {
setLastActionWasSwipe, setLastActionWasSwipe,
setIsPlotProgression, setIsPlotProgression,
updateLastGeneratedData, updateLastGeneratedData,
updateCommittedTrackerData updateCommittedTrackerData,
FALLBACK_AVATAR_DATA_URI
} from '../../core/state.js'; } from '../../core/state.js';
import { saveChatData, loadChatData } from '../../core/persistence.js'; import { saveChatData, loadChatData } from '../../core/persistence.js';
@@ -291,11 +292,12 @@ export function onMessageSwiped(messageIndex) {
/** /**
* Update the persona avatar image when user switches personas * Update the persona avatar image when user switches personas
* Updates ALL .rpg-user-portrait elements with proper fallback handling
*/ */
export function updatePersonaAvatar() { export function updatePersonaAvatar() {
const portraitImg = document.querySelector('.rpg-user-portrait'); const portraitImgs = document.querySelectorAll('.rpg-user-portrait');
if (!portraitImg) { if (portraitImgs.length === 0) {
// console.log('[RPG Companion] Portrait image element not found in DOM'); // console.log('[RPG Companion] No portrait image elements found in DOM');
return; return;
} }
@@ -303,24 +305,27 @@ export function updatePersonaAvatar() {
const context = getContext(); const context = getContext();
const currentUserAvatar = context.user_avatar || user_avatar; const currentUserAvatar = context.user_avatar || user_avatar;
// console.log('[RPG Companion] Attempting to update persona avatar:', currentUserAvatar); // console.log('[RPG Companion] Updating', portraitImgs.length, 'avatar(s) for:', currentUserAvatar);
// Try to get a valid thumbnail URL using our safe helper // Update each avatar instance
if (currentUserAvatar) { portraitImgs.forEach(portraitImg => {
const thumbnailUrl = getSafeThumbnailUrl('persona', currentUserAvatar); // getSafeThumbnailUrl already calls getThumbnailUrl and handles errors
// It returns proper URLs like /thumbnail?type=persona&file=... or null
const thumbnailUrl = currentUserAvatar ? getSafeThumbnailUrl('persona', currentUserAvatar) : null;
const finalUrl = thumbnailUrl || FALLBACK_AVATAR_DATA_URI;
if (thumbnailUrl) { // Set the avatar URL
// Only update the src if we got a valid URL portraitImg.src = finalUrl;
portraitImg.src = thumbnailUrl;
// console.log('[RPG Companion] Persona avatar updated successfully'); // Add onerror handler to use fallback if load fails (404, etc.)
} else { portraitImg.onerror = () => {
// Don't update the src if we couldn't get a valid URL if (portraitImg.src !== FALLBACK_AVATAR_DATA_URI) {
// This prevents 400 errors and keeps the existing image // console.warn('[RPG Companion] Avatar failed to load, using fallback');
// console.warn('[RPG Companion] Could not get valid thumbnail URL for persona avatar, keeping existing image'); portraitImg.src = FALLBACK_AVATAR_DATA_URI;
} portraitImg.onerror = null; // Prevent infinite loop
} else { }
// console.log('[RPG Companion] No user avatar configured, keeping existing image'); };
} });
} }
/** /**