diff --git a/src/components/viewer/PsImage.ts b/src/components/viewer/PsImage.ts index a2d9d420..2ff7ae2d 100644 --- a/src/components/viewer/PsImage.ts +++ b/src/components/viewer/PsImage.ts @@ -80,7 +80,7 @@ export default class ImageContentSetup { } zoomPanUpdate({ slide }: { slide: PsSlide }) { - if (!slide.data.highSrc || slide.data.highSrcCond !== 'zoom') return; + if (!slide.data.highSrc.length || slide.data.highSrcCond !== 'zoom') return; if (slide.currZoomLevel >= slide.zoomLevels.secondary) { this.loadFullImage(slide); @@ -94,8 +94,8 @@ export default class ImageContentSetup { } } - loadFullImage(slide: PsSlide) { - if (!slide.data.highSrc) return; + async loadFullImage(slide: PsSlide) { + if (!slide.data.highSrc.length) return; // Get ximg element const img = slide.holderElement?.querySelector('.ximg:not(.ximg--full)') as HTMLImageElement; @@ -110,17 +110,21 @@ export default class ImageContentSetup { this.loading++; this.lightbox.ui?.updatePreloaderVisibility(); - fetchImage(slide.data.highSrc) - .then((blobSrc) => { + for (const src of slide.data.highSrc) { + try { + const blobSrc = await fetchImage(src); + // Check if destroyed already if (!slide.content.element) return; - // Set src img.src = blobSrc; - }) - .finally(() => { - this.loading--; - this.lightbox.ui?.updatePreloaderVisibility(); - }); + break; // success + } catch { + // go on to next image + } + } + + this.loading--; + this.lightbox.ui?.updatePreloaderVisibility(); } } diff --git a/src/components/viewer/Viewer.vue b/src/components/viewer/Viewer.vue index 324245f2..7717e558 100644 --- a/src/components/viewer/Viewer.vue +++ b/src/components/viewer/Viewer.vue @@ -803,17 +803,24 @@ export default defineComponent({ this.loadMetadata(photo); // Get full image URL - const fullUrl = isvideo - ? null - : utils.isLocalPhoto(photo) - ? nativex.API.IMAGE_FULL(photo.fileid) - : API.IMAGE_DECODABLE(photo.fileid, photo.etag); - const fullLoadCond = this.config.high_res_cond || this.config.high_res_cond_default || 'zoom'; + const highSrc: string[] = []; + if (!isvideo) { + // Try local file if NativeX is available + if (photo.auid && nativex.has()) { + highSrc.push(nativex.API.IMAGE_FULL(photo.auid)); + } + + // Decodable full resolution image + highSrc.push(API.IMAGE_DECODABLE(photo.fileid, photo.etag)); + } + + // Condition of loading full resolution image + const highSrcCond = this.config.high_res_cond || this.config.high_res_cond_default || 'zoom'; return { src: previewUrl, - highSrc: fullUrl, - highSrcCond: fullLoadCond, + highSrc: highSrc, + highSrcCond: highSrcCond, width: w || undefined, height: h || undefined, thumbCropped: true, diff --git a/src/components/viewer/types.ts b/src/components/viewer/types.ts index 9b75fcea..f9983ddc 100644 --- a/src/components/viewer/types.ts +++ b/src/components/viewer/types.ts @@ -9,7 +9,7 @@ type PsAugment = { /** The original photo object. */ photo: IPhoto; /** The source of the high resolution image. */ - highSrc: string | null; + highSrc: string[]; /** The condition for loading the high resolution image. */ highSrcCond: IConfig['high_res_cond']; /** The type of content. */ diff --git a/src/native.ts b/src/native.ts index b5b572f6..7f58a0f9 100644 --- a/src/native.ts +++ b/src/native.ts @@ -51,10 +51,10 @@ export const API = { /** * Local photo full API. * @regex ^/image/full/\d+$ - * @param fileId File ID of the photo + * @param auid AUID of the photo * @returns {Blob} JPEG full image of the photo. */ - IMAGE_FULL: (fileId: number) => `${BASE_URL}/image/full/${fileId}`, + IMAGE_FULL: (auid: number) => `${BASE_URL}/image/full/${auid}`, /** * Share a URL with native page.