Skip to content

Commit 74b4898

Browse files
committed
fix(image): simplify image fetching logic
1 parent 012243b commit 74b4898

File tree

5 files changed

+67
-56
lines changed

5 files changed

+67
-56
lines changed

src/components/common/list/ListScroll.vue

+3-1
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ const {
146146
backdrop,
147147
hidePoster,
148148
scrollBoundary,
149+
posterType,
149150
} = toRefs(props);
150151
151152
const { floating, reverse } = useAppStateStoreRefs();
@@ -155,6 +156,7 @@ const scrolled = ref(false);
155156
156157
const isCompact = watchMedia('(max-width: 600px)');
157158
const showBackdrop = computed(() => backdrop?.value && !isCompact.value);
159+
const overridePanelType = computed(() => (isCompact.value ? 'show' : posterType?.value));
158160
159161
const isTiny = watchMedia('(max-width: 350px)');
160162
const showPoster = computed(() => !hidePoster?.value && !isTiny.value);
@@ -307,7 +309,7 @@ const listPaddingBottom = computed(() => {
307309
:hide-time="hideTime"
308310
:hide-poster="!showPoster"
309311
:backdrop="showBackdrop"
310-
:poster-type="posterType"
312+
:poster-type="overridePanelType"
311313
:content-height="contentHeight"
312314
:hover="hoverDate === item.date?.current?.toDateString()"
313315
:scroll-into-view="scrollIntoView?.includes(item.id)"

src/components/common/poster/PosterComponent.vue

+30-16
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,16 @@
11
<script lang="ts" setup>
22
import { NImage } from 'naive-ui';
33
4-
import { computed, onBeforeUnmount, type PropType, ref, toRefs, watch } from 'vue';
4+
import {
5+
computed,
6+
onBeforeUnmount,
7+
type PropType,
8+
reactive,
9+
ref,
10+
toRaw,
11+
toRefs,
12+
watch,
13+
} from 'vue';
514
615
import type { PosterItem } from '~/models/poster.model';
716
@@ -36,19 +45,18 @@ const props = defineProps({
3645
3746
const { backdrop, poster, item, size, type } = toRefs(props);
3847
39-
// Local poster is used when the item has no poster ref of its own.
40-
const localPoster = ref<ImageStoreMedias>();
41-
4248
// cache poster image to prevent flickering
43-
const cache: Map<string, ImageStoreMedias> = new Map();
49+
const cache = reactive<Record<string, ImageStoreMedias>>({});
4450
45-
const resolvedPoster = computed(() => {
51+
const resolvedPoster = computed<string | undefined>(() => {
4652
if (poster?.value) return poster.value;
4753
if (item.value.poster) return item.value.poster;
48-
let image = (item.value.posterRef ?? localPoster)?.value;
49-
if (item?.value?.key) {
50-
if (image) cache.set(item.value.key, image);
51-
else image = cache.get(item.value.key);
54+
55+
let image: ImageStoreMedias | undefined = item.value.posterRef?.value;
56+
if (!image) {
57+
if (!item.value.key) return;
58+
const key = [item.value.key, backdrop.value, type?.value].filter(Boolean).join('-');
59+
image = cache[key];
5260
}
5361
if (!image) return;
5462
if (typeof image === 'string') return image;
@@ -83,13 +91,16 @@ const onLoad = () => {
8391
const { getImageUrl } = useImageStore();
8492
8593
const timeout = ref();
86-
const getPosters = async (_item: PosterItem) => {
94+
const getPosters = async (
95+
_item: PosterItem = item.value,
96+
_type: PosterItem['type'] | undefined = type?.value,
97+
) => {
8798
if (resolvedPoster.value) return;
8899
89100
const query = _item.getPosterQuery?.();
90101
if (!query) return;
91-
if (type?.value && type.value !== _item.type) {
92-
query.type = type.value;
102+
if (_type === 'show' && (_item.type === 'season' || _item.type === 'episode')) {
103+
query.type = _type;
93104
if (_item.type === 'episode') delete query.episode;
94105
if (_item.type === 'season') delete query.season;
95106
}
@@ -100,17 +111,20 @@ const getPosters = async (_item: PosterItem) => {
100111
transition.value = true;
101112
}, 100);
102113
try {
103-
await getImageUrl({
114+
const response = await getImageUrl({
104115
query,
105116
size: size.value,
106-
response: _item.posterRef ?? localPoster,
107117
});
118+
if (!_item?.key || !response) return;
119+
const key = [item.value.key, backdrop.value, type?.value].filter(Boolean).join('-');
120+
cache[key] = response;
121+
console.info('caching', query, key, response, toRaw(cache));
108122
} catch (error) {
109123
Logger.error('Failed to fetch poster', error);
110124
}
111125
};
112126
113-
watch(item, getPosters, { immediate: true, flush: 'pre' });
127+
watch([item, type, backdrop], () => getPosters(), { immediate: true, flush: 'pre' });
114128
115129
onBeforeUnmount(() => {
116130
clearTimeout(timeout.value);

src/components/views/panel/PanelPoster.vue

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<script lang="ts" setup>
22
import { NFlex, NSkeleton } from 'naive-ui';
3-
import { computed, type PropType, ref, toRefs, Transition } from 'vue';
3+
import { computed, type PropType, toRefs, Transition } from 'vue';
44
55
import type { PosterItem } from '~/models/poster.model';
66
import type { ImageQuery, ImageStoreTypes } from '~/stores/data/image.store';
@@ -59,7 +59,9 @@ const posterItem = computed<PosterItem | undefined>(() => {
5959
};
6060
6161
return {
62-
posterRef: ref(),
62+
id,
63+
key: `${type}-${id}`,
64+
type,
6365
getPosterQuery: () => imageQuery,
6466
};
6567
});

src/models/poster.model.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@ import type { Ref } from 'vue';
33
import type { ImageQuery, ImageStoreMedias, ImageStoreTypes } from '~/stores/data/image.store';
44

55
export type PosterItem = {
6-
type?: ImageStoreTypes;
7-
key?: string;
6+
id: string | number;
7+
key: string;
8+
type: ImageStoreTypes;
89

910
poster?: string;
1011
posterRef?: Ref<ImageStoreMedias | undefined>;

src/stores/data/image.store.ts

+27-35
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { arrayMax, findClosestMatch } from '@dvcol/common-utils/common/math';
22
import { getShortLocale } from '@dvcol/common-utils/common/navigator';
33
import { defineStore, storeToRefs } from 'pinia';
44

5-
import { computed, reactive, type Ref, ref } from 'vue';
5+
import { computed, reactive, ref } from 'vue';
66

77
import type { TmdbConfiguration, TmdbImage } from '@dvcol/tmdb-http-client/models';
88

@@ -232,66 +232,58 @@ export const useImageStore = defineStore(ImageStoreConstants.Store, () => {
232232
const buildImageUrl = ({ url, baseUrl, type, size }: { url: string; baseUrl: string; type: ImageQuery['type']; size: number | 'original' }) =>
233233
`${baseUrl}${getImageSize(type, size)}${url}`;
234234

235-
const setResponseValue = (
236-
{ image, baseUrl, type, size }: { image: ImageStoreMedias; baseUrl: string; type: ImageQuery['type']; size: number | 'original' },
237-
response: Ref<ImageStoreMedias | undefined> = ref(),
238-
): Ref<ImageStoreMedias | undefined> => {
239-
if (typeof image === 'string') response.value = buildImageUrl({ url: image, baseUrl, type, size });
240-
else {
241-
response.value = {
242-
poster: image.poster ? buildImageUrl({ url: image.poster, baseUrl, type, size }) : undefined,
243-
backdrop: image.backdrop ? buildImageUrl({ url: image.backdrop, baseUrl, type, size }) : undefined,
244-
};
245-
}
246-
return response;
235+
const getResponseValue = ({
236+
image,
237+
baseUrl,
238+
type,
239+
size,
240+
}: {
241+
image?: ImageStoreMedias;
242+
baseUrl?: string;
243+
type: ImageQuery['type'];
244+
size: number | 'original';
245+
}): ImageStoreMedias | undefined => {
246+
if (!baseUrl || !image) return undefined;
247+
if (typeof image === 'string') return buildImageUrl({ url: image, baseUrl, type, size });
248+
249+
return {
250+
poster: image.poster ? buildImageUrl({ url: image.poster, baseUrl, type, size }) : undefined,
251+
backdrop: image.backdrop ? buildImageUrl({ url: image.backdrop, baseUrl, type, size }) : undefined,
252+
};
247253
};
248254

249255
const getImageResponse = ({
250256
query,
251257
size = 300,
252-
response = ref(),
253258
}: {
254259
query: ImageQuery;
255260
size?: number | 'original';
256-
response?: Ref<ImageStoreMedias | undefined>;
257261
}): {
258-
response: Ref<ImageStoreMedias | undefined>;
259262
key: string;
260263
type: ImageQuery['type'];
261-
image?: string | ImageStoreMedias;
264+
image?: ImageStoreMedias;
262265
baseUrl?: string;
263266
} => {
264267
const { key, type } = getKeyAndType(query);
265268
const image = images[type][key];
266269
const baseUrl = tmdbConfig.value?.images?.secure_base_url;
267-
if (image && baseUrl) setResponseValue({ image, baseUrl, type, size }, response);
268-
return { response, key, type, image, baseUrl };
270+
return { key, type, baseUrl, image: getResponseValue({ image, baseUrl, type, size }) };
269271
};
270272

271-
const getImageUrl = async ({
272-
query,
273-
size = 300,
274-
response = ref(),
275-
fetch = true,
276-
}: {
277-
query: ImageQuery;
278-
size?: number | 'original';
279-
response?: Ref<ImageStoreMedias | undefined>;
280-
fetch?: boolean;
281-
}) => {
273+
const getImageUrl = async ({ query, size = 300, fetch = true }: { query: ImageQuery; size?: number | 'original'; fetch?: boolean }) => {
282274
if (!tmdbConfig.value) throw new Error('TmdbConfiguration not initialized');
283275
if (!tmdbConfig.value?.images?.secure_base_url) throw new Error('TmdbConfiguration missing secure_base_url');
284276

285-
const { image, key, type, baseUrl = tmdbConfig.value.images.secure_base_url } = getImageResponse({ query, size, response });
277+
const { image, key, type, baseUrl = tmdbConfig.value.images.secure_base_url } = getImageResponse({ query, size });
286278

287-
if (image || !fetch) return response;
279+
if (image || !fetch) return image;
288280

289281
const result = await fetchImageUrl(key, query);
290-
if (!result?.image) return response;
291-
return setResponseValue({ image: result.image, baseUrl, type, size }, response);
282+
if (!result?.image) return undefined;
283+
return getResponseValue({ image: result.image, baseUrl, type, size });
292284
};
293285

294-
return { initImageStore, getImageUrl, getImageResponse, imageSizes, clearState, buildImageUrl };
286+
return { initImageStore, getImageUrl, imageSizes, clearState, buildImageUrl };
295287
});
296288

297289
export const useImageStoreRefs = () => storeToRefs(useImageStore());

0 commit comments

Comments
 (0)