139 lines
4.0 KiB
Vue
139 lines
4.0 KiB
Vue
<script setup lang="ts">
|
|
import type { ArtistCredit, Album, Library, Track } from '~/types'
|
|
|
|
import LibraryWidget from '~/components/federation/LibraryWidget.vue'
|
|
import ChannelEntries from '~/components/audio/ChannelEntries.vue'
|
|
import TrackTable from '~/components/audio/track/Table.vue'
|
|
import PlayButton from '~/components/audio/PlayButton.vue'
|
|
import Pagination from '~/components/vui/Pagination.vue'
|
|
import { computed, ref } from 'vue'
|
|
|
|
interface Events {
|
|
(e: 'libraries-loaded', libraries: Library[]): void
|
|
}
|
|
|
|
interface Props {
|
|
object: Album
|
|
|
|
isLoadingTracks: boolean
|
|
isSerie: boolean
|
|
artistCredit: ArtistCredit[]
|
|
paginateBy: number
|
|
totalTracks: number
|
|
}
|
|
|
|
const emit = defineEmits<Events>()
|
|
const props = defineProps<Props>()
|
|
|
|
const getDiscKey = (disc: Track[]) => disc?.map(track => track.id).join('|') ?? ''
|
|
const page = ref(1)
|
|
|
|
const discCount = computed(() => props.object.tracks.reduce((acc, track) => {
|
|
acc.add(track.disc_number)
|
|
return acc
|
|
}, new Set()).size)
|
|
|
|
const discs = computed(() => props.object.tracks
|
|
.reduce((acc: Track[][], track: Track) => {
|
|
const discNumber = track.disc_number - (props.object.tracks[0]?.disc_number ?? 1)
|
|
acc[discNumber].push(track)
|
|
return acc
|
|
}, Array(discCount.value).fill(undefined).map(() => []))
|
|
)
|
|
|
|
const paginatedDiscs = computed(() => props.object.tracks.slice(props.paginateBy * (page.value - 1), props.paginateBy * page.value)
|
|
.reduce((acc: Track[][], track: Track) => {
|
|
const discNumber = track.disc_number - (props.object.tracks[0]?.disc_number ?? 1)
|
|
acc[discNumber].push(track)
|
|
return acc
|
|
}, Array(discCount.value).fill(undefined).map(() => []))
|
|
)
|
|
|
|
</script>
|
|
|
|
<template>
|
|
<div
|
|
v-if="!isLoadingTracks"
|
|
class="ui vertical segment"
|
|
>
|
|
<h2 class="ui header">
|
|
<span v-if="isSerie">
|
|
{{ $t('components.library.AlbumDetail.header.episodes') }}
|
|
</span>
|
|
<span v-else>
|
|
{{ $t('components.library.AlbumDetail.header.tracks') }}
|
|
</span>
|
|
</h2>
|
|
|
|
<channel-entries
|
|
v-if="artistCredit && artistCredit[0].artist.channel && isSerie"
|
|
:is-podcast="isSerie"
|
|
:limit="50"
|
|
:filters="{channel: artistCredit[0].artist.channel.uuid, album: object.id, ordering: '-creation_date'}"
|
|
/>
|
|
|
|
<template v-else>
|
|
<template v-if="discCount > 1">
|
|
<div
|
|
v-for="tracks, index in paginatedDiscs"
|
|
:key="index + getDiscKey(tracks)"
|
|
>
|
|
<template v-if="tracks.length > 0">
|
|
<div class="ui hidden divider" />
|
|
<play-button
|
|
class="right floated mini inverted vibrant"
|
|
:tracks="discs[index]"
|
|
/>
|
|
<h3>
|
|
{{ $t('components.library.AlbumDetail.meta.volume', {number: tracks[0].disc_number}) }}
|
|
</h3>
|
|
<track-table
|
|
:is-album="true"
|
|
:tracks="tracks"
|
|
:show-position="true"
|
|
:show-art="false"
|
|
:show-album="false"
|
|
:show-artist="false"
|
|
:paginate-results="false"
|
|
/>
|
|
</template>
|
|
</div>
|
|
</template>
|
|
<template v-else>
|
|
<track-table
|
|
:is-album="true"
|
|
:tracks="object.tracks"
|
|
:show-position="true"
|
|
:show-art="false"
|
|
:show-album="false"
|
|
:show-artist="false"
|
|
:paginate-results="false"
|
|
/>
|
|
</template>
|
|
|
|
<div
|
|
v-if="totalTracks > paginateBy"
|
|
class="ui center aligned basic segment"
|
|
>
|
|
<pagination
|
|
v-model:current="page"
|
|
:paginate-by="paginateBy"
|
|
:total="totalTracks"
|
|
/>
|
|
</div>
|
|
</template>
|
|
|
|
<template v-if="artistCredit && !artistCredit[0]?.artist.channel && !isSerie">
|
|
<h2>
|
|
{{ $t('components.library.AlbumDetail.header.libraries') }}
|
|
</h2>
|
|
<library-widget
|
|
:url="'albums/' + object.id + '/libraries/'"
|
|
@loaded="emit('libraries-loaded', $event)"
|
|
>
|
|
{{ $t('components.library.AlbumDetail.description.libraries') }}
|
|
</library-widget>
|
|
</template>
|
|
</div>
|
|
</template>
|