From 3200ad919d0c05279618bae00a47c32629db4b4c Mon Sep 17 00:00:00 2001 From: AlejandroAkbal <37181533+AlejandroAkbal@users.noreply.github.com> Date: Sat, 14 Mar 2026 06:28:23 -0700 Subject: [PATCH] fix: hide broken media posts in feed --- components/pages/posts/post/PostComponent.vue | 6 ++ components/pages/posts/post/PostMedia.vue | 5 ++ pages/posts/[domain].vue | 63 +++++++++++++++---- test/pages/posts.test.ts | 25 +++----- 4 files changed, 70 insertions(+), 29 deletions(-) diff --git a/components/pages/posts/post/PostComponent.vue b/components/pages/posts/post/PostComponent.vue index 0338471b..d128dec1 100644 --- a/components/pages/posts/post/PostComponent.vue +++ b/components/pages/posts/post/PostComponent.vue @@ -21,8 +21,13 @@ addTag: [tag: string] setTag: [tag: string] openTagInNewTab: [tag: string] + mediaError: [postId: number] }>() + function onMediaError() { + emit('mediaError', props.post.id) + } + const currentUrl = useRequestURL() const { postFullSizeImages } = useUserSettings() @@ -108,6 +113,7 @@ :mediaSrcWidth="mediaFile.width" :mediaType="post.media_type" :postIndex="props.postIndex" + @mediaError="onMediaError" />
diff --git a/components/pages/posts/post/PostMedia.vue b/components/pages/posts/post/PostMedia.vue index ac543f1b..5af21766 100644 --- a/components/pages/posts/post/PostMedia.vue +++ b/components/pages/posts/post/PostMedia.vue @@ -29,6 +29,10 @@ const props = defineProps() + const emit = defineEmits<{ + mediaError: [] + }>() + const isMainHost = computed(() => import.meta.dev || requestUrl.hostname === project.urls.production.hostname) const mediaElement = ref(null) @@ -337,6 +341,7 @@ } error.value = new Error('Error loading media') + emit('mediaError') } function manuallyReloadMedia() { diff --git a/pages/posts/[domain].vue b/pages/posts/[domain].vue index d2182468..b0134261 100644 --- a/pages/posts/[domain].vue +++ b/pages/posts/[domain].vue @@ -34,23 +34,27 @@ onMounted(() => { const hasLoadedAds = ref(false) - watch([hasInteracted, isPremium], ([hasInteracted, isPremium]) => { - if (hasLoadedAds.value) { - return - } + watch( + [hasInteracted, isPremium], + ([hasInteracted, isPremium]) => { + if (hasLoadedAds.value) { + return + } - if (!hasInteracted) { - return - } + if (!hasInteracted) { + return + } - if (isPremium) { - return - } + if (isPremium) { + return + } - hasLoadedAds.value = true + hasLoadedAds.value = true - useAdvertisements() - }, { immediate: true }) + useAdvertisements() + }, + { immediate: true } + ) }) /** @@ -375,6 +379,34 @@ window.location.reload() } + const hiddenPostMediaErrorKeys = ref([]) + + const hiddenPostMediaErrorScopeKey = computed(() => { + return JSON.stringify({ + domain: selectedBooru.value.domain, + tags: selectedTags.value.map((tag) => tag.name), + filters: selectedFilters.value + }) + }) + + function getPostMediaErrorKey(postId: number) { + return `${selectedBooru.value.domain}-${postId}` + } + + function onPostMediaError(postId: number) { + const postMediaErrorKey = getPostMediaErrorKey(postId) + + if (hiddenPostMediaErrorKeys.value.includes(postMediaErrorKey)) { + return + } + + hiddenPostMediaErrorKeys.value.push(postMediaErrorKey) + } + + watch(hiddenPostMediaErrorScopeKey, () => { + hiddenPostMediaErrorKeys.value = [] + }) + /** * Data fetching */ @@ -554,6 +586,10 @@ // return page.data.flatMap((post, index) => { + if (hiddenPostMediaErrorKeys.value.includes(getPostMediaErrorKey(post.id))) { + return [] + } + // return { @@ -1059,6 +1095,7 @@ :postIndex="virtualRow.index" :selectedTags="selectedTags" @addTag="onPostAddTag" + @mediaError="onPostMediaError" @openTagInNewTab="onPostOpenTagInNewTab" @setTag="onPostSetTag" /> diff --git a/test/pages/posts.test.ts b/test/pages/posts.test.ts index a32047e5..1cf3fe41 100644 --- a/test/pages/posts.test.ts +++ b/test/pages/posts.test.ts @@ -1,12 +1,12 @@ -import {describe, expect, it} from 'vitest' -import {createPage, setup, url} from '@nuxt/test-utils' +import { describe, expect, it } from 'vitest' +import { createPage, setup, url } from '@nuxt/test-utils' import { mockPostsPage0, mockPostsPage1, mockPostsPageWithOfflineMedia, mockPostsPageWithoutResults } from './posts.mock-data' -import {defaultSetupConfig} from '../helper' +import { defaultSetupConfig } from '../helper' describe('/', async () => { await setup(defaultSetupConfig) @@ -127,7 +127,7 @@ describe('/', async () => { throw new Error('Not implemented') }) - it('renders warning when media failed to load', async () => { + it('hides post when media failed to load in feed', async () => { // Arrange const page = await createPage() @@ -151,23 +151,16 @@ describe('/', async () => { await Promise.all([ page.goto(url('/posts/safebooru.org')), page.waitForResponse('**/posts?baseEndpoint=*'), - - await page.waitForRequest('**/example.local/**') + page.waitForRequest('**/example.local/**') ]) // Assert - // Expect 1 post - expect( - // - await page.getByTestId('posts-list').locator('li').count() - ).toBe(1) + // Expect post to be hidden after media fails + expect(await page.getByRole('heading', { name: /no results/i }).isVisible()).toBe(true) - // Expect post to have warning - expect( - // - await page.getByTestId('posts-list').locator('li').first().textContent() - ).toContain('Error loading media') + // Expect no media error placeholder to remain in feed + expect(await page.getByText('Error loading media').count()).toBe(0) }) })