fix(front): Correct fallback cover images for activity list in user profile
This commit is contained in:
parent
9af9dc4a3f
commit
fc10fca736
|
@ -1,10 +1,11 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { Track, Listening } from '~/types'
|
import type { Track, Listening } from '~/types'
|
||||||
|
|
||||||
import { ref, reactive, watch } from 'vue'
|
import { ref, reactive, watch, computed } from 'vue'
|
||||||
import { useStore } from '~/store'
|
import { useStore } from '~/store'
|
||||||
import { clone } from 'lodash-es'
|
import { clone } from 'lodash-es'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
|
import { getArtistCoverUrl } from '~/utils/utils'
|
||||||
|
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
|
|
||||||
|
@ -14,10 +15,10 @@ import PlayButton from '~/components/audio/PlayButton.vue'
|
||||||
import TagsList from '~/components/tags/List.vue'
|
import TagsList from '~/components/tags/List.vue'
|
||||||
import Alert from '~/components/ui/Alert.vue'
|
import Alert from '~/components/ui/Alert.vue'
|
||||||
import Spacer from '~/components/ui/Spacer.vue'
|
import Spacer from '~/components/ui/Spacer.vue'
|
||||||
|
import Loader from '~/components/ui/Loader.vue'
|
||||||
|
|
||||||
import useErrorHandler from '~/composables/useErrorHandler'
|
import useErrorHandler from '~/composables/useErrorHandler'
|
||||||
|
|
||||||
import { getArtistCoverUrl } from '~/utils/utils'
|
|
||||||
|
|
||||||
interface Events {
|
interface Events {
|
||||||
(e: 'count', count: number): void
|
(e: 'count', count: number): void
|
||||||
|
@ -84,14 +85,48 @@ watch(
|
||||||
watch(count, (to) => emit('count', to))
|
watch(count, (to) => emit('count', to))
|
||||||
|
|
||||||
watch(() => props.websocketHandlers.includes('Listen'), (to) => {
|
watch(() => props.websocketHandlers.includes('Listen'), (to) => {
|
||||||
useWebSocketHandler('Listen', (event) => {
|
if (to) {
|
||||||
// TODO (wvffle): Add reactivity to recently listened / favorited / added (#1316, #1534)
|
useWebSocketHandler('Listen', (event) => {
|
||||||
// count.value += 1
|
// Handle WebSocket events for "Listen"
|
||||||
|
|
||||||
// objects.unshift(event as Listening)
|
// Add the event to `objects` reactively
|
||||||
// objects.pop()
|
objects.unshift(event as Listening);
|
||||||
})
|
|
||||||
})
|
// Keep the array size within limits (e.g., remove the last item if needed)
|
||||||
|
if (objects.length > props.limit) {
|
||||||
|
objects.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recompute coverUrl for the updated `objects`
|
||||||
|
console.log('WebSocket event received:', event);
|
||||||
|
console.log('Updated cover URL:', coverUrl.value);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(
|
||||||
|
objects,
|
||||||
|
(newObjects) => {
|
||||||
|
// Process each object to attach a `coverUrl`
|
||||||
|
newObjects.forEach((object) => {
|
||||||
|
const track = object.track;
|
||||||
|
if (!("coverUrl" in object)) {
|
||||||
|
object.coverUrl = undefined; // Initial value for clarity
|
||||||
|
}
|
||||||
|
|
||||||
|
if (track?.album?.cover) {
|
||||||
|
object.coverUrl = store.getters["instance/absoluteUrl"](track.album.cover.urls.medium_square_crop);
|
||||||
|
} else if (track?.cover) {
|
||||||
|
object.coverUrl = store.getters["instance/absoluteUrl"](track.cover.urls.medium_square_crop);
|
||||||
|
} else if (track?.artist_credit?.length > 0) {
|
||||||
|
object.coverUrl = getArtistCoverUrl(track.artist_credit) || false;
|
||||||
|
} else {
|
||||||
|
object.coverUrl = false; // Fallback if no cover is found
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
{ deep: true }
|
||||||
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -120,26 +155,15 @@ watch(() => props.websocketHandlers.includes('Listen'), (to) => {
|
||||||
@click="navigate('track')"
|
@click="navigate('track')"
|
||||||
>
|
>
|
||||||
<div class="activity-image">
|
<div class="activity-image">
|
||||||
<img
|
<img
|
||||||
v-if="object.track.album && object.track.album.cover"
|
v-if="object.coverUrl"
|
||||||
v-lazy="store.getters['instance/absoluteUrl'](object.track.album.cover.urls.medium_square_crop)"
|
v-lazy="object.coverUrl"
|
||||||
alt=""
|
alt="Cover"
|
||||||
>
|
/>
|
||||||
<img
|
<i
|
||||||
v-else-if="object.track.cover"
|
|
||||||
v-lazy="store.getters['instance/absoluteUrl'](object.track.cover.urls.medium_square_crop)"
|
|
||||||
alt=""
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
v-else-if="object.track.artist_credit && object.track.artist_credit.length > 0"
|
|
||||||
v-lazy="getArtistCoverUrl(object.track.artist_credit)"
|
|
||||||
alt=""
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
v-else
|
v-else
|
||||||
alt=""
|
class="bi bi-vinyl-fill"
|
||||||
src="../../../../public/embed-default-cover.jpeg"
|
/>
|
||||||
>
|
|
||||||
<PlayButton
|
<PlayButton
|
||||||
class="play-overlay"
|
class="play-overlay"
|
||||||
:icon-only="true"
|
:icon-only="true"
|
||||||
|
@ -250,6 +274,10 @@ watch(() => props.websocketHandlers.includes('Listen'), (to) => {
|
||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
> i {
|
||||||
|
font-size: 36px;
|
||||||
|
}
|
||||||
|
|
||||||
> .play-button {
|
> .play-button {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
|
|
|
@ -85,6 +85,7 @@ const fetchData = async () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
watch(props, fetchData, { immediate: true })
|
watch(props, fetchData, { immediate: true })
|
||||||
|
const recentActivity = ref(0)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -140,12 +141,12 @@ watch(props, fetchData, { immediate: true })
|
||||||
<h2 class="ui with-actions header">
|
<h2 class="ui with-actions header">
|
||||||
{{ t('views.auth.ProfileOverview.header.libraries') }}
|
{{ t('views.auth.ProfileOverview.header.libraries') }}
|
||||||
<div
|
<div
|
||||||
v-if="store.state.auth.authenticated && object.full_username === store.state.auth.fullUsername"
|
v-if="store.state.auth.authenticated && object?.full_username === store.state.auth.fullUsername"
|
||||||
class="actions"
|
class="actions"
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
</h2>
|
</h2>
|
||||||
<library-widget :url="`federation/actors/${object.full_username}/libraries/`">
|
<library-widget :url="`federation/actors/${object?.full_username}/libraries/`">
|
||||||
<template #title>
|
<template #title>
|
||||||
{{ t('views.auth.ProfileOverview.header.sharedLibraries') }}
|
{{ t('views.auth.ProfileOverview.header.sharedLibraries') }}
|
||||||
</template>
|
</template>
|
||||||
|
@ -156,7 +157,7 @@ watch(props, fetchData, { immediate: true })
|
||||||
<h2 class="ui with-actions header">
|
<h2 class="ui with-actions header">
|
||||||
{{ t('views.auth.ProfileOverview.header.channels') }}
|
{{ t('views.auth.ProfileOverview.header.channels') }}
|
||||||
<div
|
<div
|
||||||
v-if="store.state.auth.authenticated && object.full_username === store.state.auth.fullUsername"
|
v-if="store.state.auth.authenticated && object?.full_username === store.state.auth.fullUsername"
|
||||||
class="actions"
|
class="actions"
|
||||||
>
|
>
|
||||||
<a
|
<a
|
||||||
|
@ -168,15 +169,16 @@ watch(props, fetchData, { immediate: true })
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</h2>
|
</h2>
|
||||||
<channels-widget :filters="{scope: `actor:${object.full_username}`}" />
|
<channels-widget :filters="{scope: `actor:${object?.full_username}`}" />
|
||||||
</Tab>
|
</Tab>
|
||||||
|
|
||||||
<Tab :title="t('views.auth.ProfileBase.link.activity')" :to="{name: 'profile.activity', params: routerParams}">
|
<Tab :title="t('views.auth.ProfileBase.link.activity')" :to="{name: 'profile.activity', params: routerParams}">
|
||||||
|
|
||||||
<track-widget
|
<track-widget
|
||||||
:url="'history/listenings/'"
|
:url="'history/listenings/'"
|
||||||
:filters="{ scope, ordering: '-creation_date', ...qualityFilters}"
|
:filters="{ scope: `actor:${object.full_username}`, ordering: '-creation_date', ...qualityFilters}"
|
||||||
:websocket-handlers="['Listen']"
|
:websocket-handlers="['Listen']"
|
||||||
|
@count="recentActivity = $event"
|
||||||
>
|
>
|
||||||
<template #title>
|
<template #title>
|
||||||
{{ t('components.library.Home.header.recentlyListened') }}
|
{{ t('components.library.Home.header.recentlyListened') }}
|
||||||
|
@ -185,14 +187,14 @@ watch(props, fetchData, { immediate: true })
|
||||||
|
|
||||||
<track-widget
|
<track-widget
|
||||||
:url="'favorites/tracks/'"
|
:url="'favorites/tracks/'"
|
||||||
:filters="{scope: scope, ordering: '-creation_date'}"
|
:filters="{scope: 'actor:${object.full_username}', ordering: '-creation_date'}"
|
||||||
>
|
>
|
||||||
<template #title>
|
<template #title>
|
||||||
{{ t('components.library.Home.header.recentlyFavorited') }}
|
{{ t('components.library.Home.header.recentlyFavorited') }}
|
||||||
</template>
|
</template>
|
||||||
</track-widget>
|
</track-widget>
|
||||||
|
|
||||||
<album-widget :filters="{scope: scope, playable: true, ordering: '-creation_date', ...qualityFilters}">
|
<album-widget :filters="{scope: `actor:${object.full_username}`, playable: true, ordering: '-creation_date', ...qualityFilters}">
|
||||||
<template #title>
|
<template #title>
|
||||||
{{ t('components.library.Home.header.recentlyAdded') }}
|
{{ t('components.library.Home.header.recentlyAdded') }}
|
||||||
</template>
|
</template>
|
||||||
|
|
Loading…
Reference in New Issue