fix(character-art): resolve full character portrait from StarRailRes jsDelivr CDN and add robust portrait fallback handler
This commit is contained in:
1 parent
b5c4dbec9e
commit
ed5e80de30
3 files changed
+82
-12
No files matched your search
+3
-2
@@ -1506,7 +1506,7 @@ input:checked + .slider:before {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
object-position: top center;
|
||||
object-position: center 25%;
|
||||
transition: transform 0.4s ease;
|
||||
}
|
||||
|
||||
@@ -2009,8 +2009,9 @@ input:checked + .slider:before {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
object-position: top center;
|
||||
object-position: center 25%;
|
||||
transition: transform 0.4s ease;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.overview-portrait-box:hover .overview-portrait-img {
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
getLightconeArtUrl,
|
||||
getLightconeThumbUrl,
|
||||
handleAvatarImgError,
|
||||
handleAvatarPortraitError,
|
||||
handleLcImgError,
|
||||
GACHABASE_IMAGE_CACHE,
|
||||
KNOWN_GACHABASE_ASSETS
|
||||
@@ -15,6 +16,7 @@ import {
|
||||
|
||||
// Expose image resolvers & error handlers to window for inline onclick/onerror attributes
|
||||
window.handleAvatarImgError = handleAvatarImgError;
|
||||
window.handleAvatarPortraitError = handleAvatarPortraitError;
|
||||
window.handleLcImgError = handleLcImgError;
|
||||
window.getAvatarIconUrl = getAvatarIconUrl;
|
||||
window.getLightconeArtUrl = getLightconeArtUrl;
|
||||
@@ -2369,7 +2371,7 @@ function getAvatarSplashSrc(aid) {
|
||||
if (meta?.images?.fullArt) return meta.images.fullArt;
|
||||
if (GACHABASE_IMAGE_CACHE.avatarSplash[id]) return GACHABASE_IMAGE_CACHE.avatarSplash[id];
|
||||
if (KNOWN_GACHABASE_ASSETS.avatarSplash[id]) return KNOWN_GACHABASE_ASSETS.avatarSplash[id];
|
||||
return `https://raw.githubusercontent.com/Mar-7th/StarRailRes/master/image/character_portrait/${id}.png`;
|
||||
return `https://cdn.jsdelivr.net/gh/Mar-7th/StarRailRes@master/image/character_portrait/${id}.png`;
|
||||
}
|
||||
|
||||
|
||||
@@ -2685,9 +2687,12 @@ function renderModalOverviewTab(avatarId) {
|
||||
|
||||
// Portrait Art
|
||||
if (el.overviewPortraitImg) {
|
||||
el.overviewPortraitImg.removeAttribute('data-err-step');
|
||||
el.overviewPortraitImg.style.display = 'block';
|
||||
el.overviewPortraitImg.style.objectFit = 'cover';
|
||||
el.overviewPortraitImg.src = getAvatarSplashSrc(aid);
|
||||
el.overviewPortraitImg.onerror = function() {
|
||||
handleAvatarImgError(this, aid);
|
||||
handleAvatarPortraitError(this, aid);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -4553,7 +4558,7 @@ function renderShowcaseCard(avatarId) {
|
||||
el.showcaseCardContainer.innerHTML = `
|
||||
<!-- 1. Left Splash Art Column -->
|
||||
<div class="showcase-splash-col">
|
||||
<img class="showcase-splash-img" src="${primaryPortrait}" onerror="if(this.src!=='${fallbackPortrait}')this.src='${fallbackPortrait}';else handleAvatarImgError(this, ${aid});" alt="${meta.name}">
|
||||
<img class="showcase-splash-img" src="${primaryPortrait}" onerror="handleAvatarPortraitError(this, ${aid})" alt="${meta.name}">
|
||||
<div class="showcase-splash-overlay">
|
||||
<div class="showcase-char-name">${meta.name}</div>
|
||||
<div style="display: flex; gap: 0.4rem; align-items: center; flex-wrap: wrap;">
|
||||
|
||||
+71
-7
@@ -17,8 +17,6 @@ export const KNOWN_GACHABASE_ASSETS = {
|
||||
},
|
||||
avatarSplash: {
|
||||
1511: 'https://cdn.gachabase.net/hsr/assets/f8b5630e85022ab8b2761e4e3f614b42.png', // Aha Splash Art (2048x1914)
|
||||
1513: 'https://cdn.gachabase.net/hsr/assets/65b90212f8623ad92243d739ea1fc9ec.png', // Waveflair Splash
|
||||
1505: 'https://cdn.gachabase.net/hsr/assets/71cbe3943310cb233e8dbe6ef69caeb1.png', // Evanescia Splash
|
||||
1502: 'https://cdn.gachabase.net/hsr/assets/8ca2530c42791593b72d54a850fce97e.png', // Yao Guang
|
||||
1501: 'https://cdn.gachabase.net/hsr/assets/09ee6e2618ac2a0dab2aec8d73b0bb01.png', // Sparxie
|
||||
},
|
||||
@@ -384,7 +382,7 @@ export function getLightconeArtUrl(lcId) {
|
||||
if (id === 23065) {
|
||||
return './assets/lightcones/23065.png';
|
||||
}
|
||||
return `https://raw.githubusercontent.com/Mar-7th/StarRailRes/master/image/light_cone_preview/${id}.png`;
|
||||
return `https://cdn.jsdelivr.net/gh/Mar-7th/StarRailRes@master/image/light_cone_preview/${id}.png`;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -401,9 +399,69 @@ export function getLightconeThumbUrl(lcId) {
|
||||
return getLightconeArtUrl(lcId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Robust error handler for Avatar Full Portrait / Splash Art
|
||||
* Falls back through:
|
||||
* 0. jsDelivr StarRailRes character_portrait (2048x2048 splash)
|
||||
* 1. jsDelivr StarRailRes character_drawing (transparent full body art)
|
||||
* 2. Raw GitHub character_portrait
|
||||
* 3. Raw GitHub character_drawing
|
||||
* 4. Gachabase splash cache
|
||||
* 5. jsDelivr avatar icon (visual fallback rather than blank)
|
||||
*/
|
||||
export function handleAvatarPortraitError(img, avatarId) {
|
||||
if (!img) return;
|
||||
const id = parseInt(avatarId, 10);
|
||||
const step = parseInt(img.getAttribute('data-err-step') || '0', 10);
|
||||
|
||||
if (step === 0) {
|
||||
img.setAttribute('data-err-step', '1');
|
||||
const portraitUrl = `https://cdn.jsdelivr.net/gh/Mar-7th/StarRailRes@master/image/character_portrait/${id}.png`;
|
||||
if (img.src !== portraitUrl) {
|
||||
img.src = portraitUrl;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (step <= 1) {
|
||||
img.setAttribute('data-err-step', '2');
|
||||
const drawingUrl = `https://cdn.jsdelivr.net/gh/Mar-7th/StarRailRes@master/image/character_drawing/${id}.png`;
|
||||
if (img.src !== drawingUrl) {
|
||||
img.src = drawingUrl;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (step <= 2) {
|
||||
img.setAttribute('data-err-step', '3');
|
||||
const rawPortrait = `https://raw.githubusercontent.com/Mar-7th/StarRailRes/master/image/character_portrait/${id}.png`;
|
||||
if (img.src !== rawPortrait) {
|
||||
img.src = rawPortrait;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (step <= 3) {
|
||||
img.setAttribute('data-err-step', '4');
|
||||
const gachaSplash = GACHABASE_IMAGE_CACHE.avatarSplash?.[id] || KNOWN_GACHABASE_ASSETS.avatarSplash?.[id];
|
||||
if (gachaSplash && img.src !== gachaSplash) {
|
||||
img.src = gachaSplash;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Step 4+: Visual fallback to avatar icon rather than ever leaving the portrait black/blank
|
||||
img.setAttribute('data-err-step', '5');
|
||||
const iconUrl = `https://cdn.jsdelivr.net/gh/Mar-7th/StarRailRes@master/icon/avatar/${id}.png`;
|
||||
if (img.src !== iconUrl) {
|
||||
img.src = iconUrl;
|
||||
img.style.objectFit = 'contain';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Robust error handler for Avatar images
|
||||
* Falls back through: Local Asset -> StarRailRes -> Gachabase CDN -> Letter Placeholder
|
||||
* Falls back through: jsDelivr StarRailRes -> Raw GitHub -> Gachabase CDN -> Letter Placeholder
|
||||
*/
|
||||
export function handleAvatarImgError(img, avatarId) {
|
||||
if (!img) return;
|
||||
@@ -412,9 +470,12 @@ export function handleAvatarImgError(img, avatarId) {
|
||||
|
||||
if (step === 0) {
|
||||
img.setAttribute('data-err-step', '1');
|
||||
img.src = `https://raw.githubusercontent.com/Mar-7th/StarRailRes/master/icon/avatar/${id}.png`;
|
||||
img.src = `https://cdn.jsdelivr.net/gh/Mar-7th/StarRailRes@master/icon/avatar/${id}.png`;
|
||||
} else if (step === 1) {
|
||||
img.setAttribute('data-err-step', '2');
|
||||
img.src = `https://raw.githubusercontent.com/Mar-7th/StarRailRes/master/icon/avatar/${id}.png`;
|
||||
} else if (step === 2) {
|
||||
img.setAttribute('data-err-step', '3');
|
||||
const gachaUrl = GACHABASE_IMAGE_CACHE.avatars[id] || KNOWN_GACHABASE_ASSETS.avatars[id];
|
||||
if (gachaUrl && img.src !== gachaUrl) {
|
||||
img.src = gachaUrl;
|
||||
@@ -434,7 +495,7 @@ export function handleAvatarImgError(img, avatarId) {
|
||||
|
||||
/**
|
||||
* Robust error handler for Lightcone images
|
||||
* Falls back through: Local Asset -> StarRailRes -> Gachabase CDN -> Default Logo
|
||||
* Falls back through: jsDelivr StarRailRes -> Raw GitHub -> Gachabase CDN -> Default Logo
|
||||
*/
|
||||
export function handleLcImgError(img, lcId) {
|
||||
if (!img) return;
|
||||
@@ -443,9 +504,12 @@ export function handleLcImgError(img, lcId) {
|
||||
|
||||
if (step === 0) {
|
||||
img.setAttribute('data-err-step', '1');
|
||||
img.src = `https://raw.githubusercontent.com/Mar-7th/StarRailRes/master/image/light_cone_preview/${id}.png`;
|
||||
img.src = `https://cdn.jsdelivr.net/gh/Mar-7th/StarRailRes@master/image/light_cone_preview/${id}.png`;
|
||||
} else if (step === 1) {
|
||||
img.setAttribute('data-err-step', '2');
|
||||
img.src = `https://raw.githubusercontent.com/Mar-7th/StarRailRes/master/image/light_cone_preview/${id}.png`;
|
||||
} else if (step === 2) {
|
||||
img.setAttribute('data-err-step', '3');
|
||||
const gachaUrl = GACHABASE_IMAGE_CACHE.lightcones[id] || KNOWN_GACHABASE_ASSETS.lightcones[id] || GACHABASE_IMAGE_CACHE.lightconeThumbs[id] || KNOWN_GACHABASE_ASSETS.lightconeThumbs[id];
|
||||
if (gachaUrl && img.src !== gachaUrl) {
|
||||
img.src = gachaUrl;
|
||||
|
||||
Reference in new issue
Block a user