Fix: add fallback to placeholder if loading thumbnail fails

This commit is contained in:
arabcoders 2025-12-18 18:58:11 +03:00
parent b36d9fd641
commit d5727ca387
3 changed files with 35 additions and 17 deletions

View file

@ -271,17 +271,17 @@
<figure :class="['image', thumbnail_ratio]">
<span v-if="'finished' === item.status && item.filename" @click="playVideo(item)" class="play-overlay">
<div class="play-icon"></div>
<img @load="(e: Event) => pImg(e)" :src="getImage(item)" v-if="getImage(item)" />
<img @load="pImg" @error="onImgError" :src="getImage(item)" v-if="getImage(item)" />
<img v-else src="/images/placeholder.png" />
</span>
<span v-else-if="isEmbedable(item.url)" @click="embed_url = getEmbedable(item.url) as string"
class="play-overlay">
<div class="play-icon embed-icon"></div>
<img @load="(e: Event) => pImg(e)" :src="getImage(item)" v-if="getImage(item)" />
<img @load="pImg" @error="onImgError" :src="getImage(item)" v-if="getImage(item)" />
<img v-else src="/images/placeholder.png" />
</span>
<template v-else>
<img @load="(e: Event) => pImg(e)" v-if="getImage(item)" :src="getImage(item)" />
<img @load="pImg" @error="onImgError" v-if="getImage(item)" :src="getImage(item)" />
<img v-else src="/images/placeholder.png" />
</template>
</figure>
@ -847,6 +847,14 @@ const pImg = (e: Event) => {
}
}
const onImgError = (e: Event) => {
const target = e.target as HTMLImageElement
if (target.src.endsWith('/images/placeholder.png')) {
return
}
target.src = '/images/placeholder.png'
}
watch(video_item, (v) => {
if (!bg_enable.value) {
return

View file

@ -193,13 +193,13 @@
<span v-if="isEmbedable(item.url)" @click="embed_url = getEmbedable(item.url) as string"
class="play-overlay">
<div class="play-icon embed-icon"></div>
<img @load="(e: Event) => pImg(e)"
<img @load="pImg" @error="onImgError"
:src="uri('/api/thumbnail?id=' + item._id + '&url=' + encodePath(item.extras.thumbnail))"
v-if="item.extras?.thumbnail" />
<img v-else src="/images/placeholder.png" />
</span>
<template v-else>
<img @load="(e: Event) => pImg(e)" v-if="item.extras?.thumbnail"
<img @load="pImg" @error="onImgError" v-if="item.extras?.thumbnail"
:src="uri('/api/thumbnail?id=' + item._id + '&url=' + encodePath(item.extras.thumbnail))" />
<img v-else src="/images/placeholder.png" />
</template>
@ -579,6 +579,14 @@ const pImg = (e: Event) => {
}
}
const onImgError = (e: Event) => {
const target = e.target as HTMLImageElement
if (target.src.endsWith('/images/placeholder.png')) {
return
}
target.src = '/images/placeholder.png'
}
watch(embed_url, v => {
if (!bg_enable.value) {
return

View file

@ -89,7 +89,8 @@
<figure class="media-left">
<figure class="image is-16by9 queue-thumb" :class="{ 'is-clickable': isEmbedable(entry.item.url) }"
role="presentation" @click="openPlayer(entry.item)">
<img :src="resolveThumbnail(entry)" :alt="entry.item.title || 'Video thumbnail'" loading="lazy">
<img :src="resolveThumbnail(entry)" :alt="entry.item.title || 'Video thumbnail'" loading="lazy"
@error="onImgError">
<span v-if="getDurationLabel(entry.item)" class="queue-thumb__badge">
{{ getDurationLabel(entry.item) }}
</span>
@ -688,18 +689,19 @@ const loadMoreHistory = async (): Promise<void> => {
}
}
// Setup intersection observer for infinite scroll
useIntersectionObserver(
loadMoreTrigger,
([entry]) => {
if (entry?.isIntersecting && !paginationInfo.value.isLoading && paginationInfo.value.page < paginationInfo.value.total_pages) {
loadMoreHistory()
}
},
{
threshold: 0.5,
const onImgError = (e: Event) => {
const target = e.target as HTMLImageElement
if (target.src.endsWith('/images/placeholder.png')) {
return
}
)
target.src = '/images/placeholder.png'
}
useIntersectionObserver(loadMoreTrigger, ([entry]) => {
if (entry?.isIntersecting && !paginationInfo.value.isLoading && paginationInfo.value.page < paginationInfo.value.total_pages) {
loadMoreHistory()
}
}, { threshold: 0.5 })
</script>