Fix play button in albums with multi-page volumes
This commit is contained in:
parent
b7355c9c95
commit
2c9327fefc
|
@ -0,0 +1 @@
|
|||
Fix play button in albums with multi-page volumes (#1928)
|
|
@ -3,7 +3,7 @@ import type { Track, Album, Artist, Library } from '~/types'
|
|||
|
||||
import { momentFormat } from '~/utils/filters'
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import { computed, reactive, ref, watch } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { sum } from 'lodash-es'
|
||||
|
||||
|
@ -29,9 +29,7 @@ const props = defineProps<Props>()
|
|||
|
||||
const object = ref<Album | null>(null)
|
||||
const artist = ref<Artist | null>(null)
|
||||
const discs = ref([] as Track[][])
|
||||
const libraries = ref([] as Library[])
|
||||
const page = ref(1)
|
||||
const paginateBy = ref(50)
|
||||
|
||||
const totalTracks = computed(() => object.value?.tracks_count ?? 0)
|
||||
|
@ -51,18 +49,7 @@ const fetchData = async () => {
|
|||
isLoading.value = true
|
||||
|
||||
const albumResponse = await axios.get(`albums/${props.id}/`, { params: { refresh: 'true' } })
|
||||
const [artistResponse, tracksResponse] = await Promise.all([
|
||||
axios.get(`artists/${albumResponse.data.artist.id}/`),
|
||||
axios.get('tracks/', {
|
||||
params: {
|
||||
ordering: 'disc_number,position',
|
||||
album: props.id,
|
||||
page_size: paginateBy.value,
|
||||
page: page.value,
|
||||
include_channels: true
|
||||
}
|
||||
})
|
||||
])
|
||||
const artistResponse = await axios.get(`artists/${albumResponse.data.artist.id}/`)
|
||||
|
||||
artist.value = artistResponse.data
|
||||
if (artist.value?.channel) {
|
||||
|
@ -71,20 +58,48 @@ const fetchData = async () => {
|
|||
|
||||
object.value = albumResponse.data
|
||||
if (object.value) {
|
||||
object.value.tracks = tracksResponse.data.results
|
||||
discs.value = object.value.tracks.reduce((acc: Track[][], track: Track) => {
|
||||
const discNumber = track.disc_number - (object.value?.tracks[0]?.disc_number ?? 1)
|
||||
acc[discNumber] ??= []
|
||||
acc[discNumber].push(track)
|
||||
return acc
|
||||
}, [])
|
||||
object.value.tracks = []
|
||||
}
|
||||
|
||||
fetchTracks()
|
||||
isLoading.value = false
|
||||
}
|
||||
|
||||
const tracks = reactive([] as Track[])
|
||||
watch(tracks, (tracks) => {
|
||||
if (object.value) {
|
||||
object.value.tracks = tracks
|
||||
}
|
||||
})
|
||||
|
||||
const isLoadingTracks = ref(false)
|
||||
const fetchTracks = async () => {
|
||||
if (isLoadingTracks.value) return
|
||||
isLoadingTracks.value = true
|
||||
tracks.length = 0
|
||||
let url = 'tracks/'
|
||||
try {
|
||||
while (url) {
|
||||
const response = await axios.get(url, {
|
||||
params: {
|
||||
ordering: 'disc_number,position',
|
||||
album: props.id,
|
||||
page_size: paginateBy.value,
|
||||
include_channels: true
|
||||
}
|
||||
})
|
||||
|
||||
url = response.data.next
|
||||
tracks.push(...response.data.results)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
} finally {
|
||||
isLoadingTracks.value = false
|
||||
}
|
||||
}
|
||||
|
||||
watch(() => props.id, fetchData, { immediate: true })
|
||||
watch(page, fetchData)
|
||||
|
||||
const router = useRouter()
|
||||
const remove = async () => {
|
||||
|
@ -337,15 +352,13 @@ const remove = async () => {
|
|||
v-if="object"
|
||||
:key="$route.fullPath"
|
||||
:paginate-by="paginateBy"
|
||||
:page="page"
|
||||
:total-tracks="totalTracks"
|
||||
:is-serie="isSerie"
|
||||
:artist="artist"
|
||||
:discs="discs"
|
||||
:object="object"
|
||||
:is-loading-tracks="isLoadingTracks"
|
||||
object-type="album"
|
||||
@libraries-loaded="libraries = $event"
|
||||
@page-changed="page = $event"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -6,32 +6,59 @@ 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: 'page-changed', page: number): void
|
||||
(e: 'libraries-loaded', libraries: Library[]): void
|
||||
}
|
||||
|
||||
interface Props {
|
||||
object: Album
|
||||
|
||||
discs: Track[][]
|
||||
|
||||
isLoadingTracks: boolean
|
||||
isSerie: boolean
|
||||
artist: Artist
|
||||
page: number
|
||||
paginateBy: number
|
||||
totalTracks: number
|
||||
}
|
||||
|
||||
const emit = defineEmits<Events>()
|
||||
defineProps<Props>()
|
||||
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(() => []))
|
||||
)
|
||||
|
||||
const getDiscKey = (disc: Track[]) => disc.map(track => track.id).join('|')
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="object">
|
||||
<div
|
||||
v-if="isLoadingTracks"
|
||||
class="ui vertical segment"
|
||||
>
|
||||
<div :class="['ui', 'centered', 'active', 'inline', 'loader']" />
|
||||
</div>
|
||||
<div v-else-if="object">
|
||||
<h2 class="ui header">
|
||||
<translate
|
||||
v-if="isSerie"
|
||||
|
@ -46,25 +73,29 @@ const getDiscKey = (disc: Track[]) => disc.map(track => track.id).join('|')
|
|||
Tracks
|
||||
</translate>
|
||||
</h2>
|
||||
|
||||
<channel-entries
|
||||
v-if="artist.channel && isSerie"
|
||||
:is-podcast="isSerie"
|
||||
:limit="50"
|
||||
:filters="{channel: artist.channel.uuid, album: object.id, ordering: '-creation_date'}"
|
||||
/>
|
||||
<template v-else-if="discs.length > 1">
|
||||
|
||||
<template v-else>
|
||||
<template v-if="discCount > 1">
|
||||
<div
|
||||
v-for="tracks in discs"
|
||||
:key="getDiscKey(tracks)"
|
||||
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="tracks"
|
||||
:tracks="discs[index]"
|
||||
/>
|
||||
<translate
|
||||
tag="h3"
|
||||
:translate-params="{number: tracks[0].disc_number}"
|
||||
:translate-params="{number: tracks[0]?.disc_number ?? index + 1}"
|
||||
translate-context="Content/Album/"
|
||||
>
|
||||
Volume %{ number }
|
||||
|
@ -78,18 +109,7 @@ const getDiscKey = (disc: Track[]) => disc.map(track => track.id).join('|')
|
|||
:show-artist="false"
|
||||
:paginate-results="false"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-if="totalTracks > paginateBy"
|
||||
class="ui center aligned basic segment tablet-and-below"
|
||||
>
|
||||
<pagination
|
||||
:current="page"
|
||||
:paginate-by="paginateBy"
|
||||
:total="totalTracks"
|
||||
:compact="true"
|
||||
@update:current="(page: number) => emit('page-changed', page)"
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
|
@ -100,13 +120,22 @@ const getDiscKey = (disc: Track[]) => disc.map(track => track.id).join('|')
|
|||
:show-art="false"
|
||||
:show-album="false"
|
||||
:show-artist="false"
|
||||
:paginate-results="true"
|
||||
:total="totalTracks"
|
||||
:paginate-by="paginateBy"
|
||||
:page="page"
|
||||
@page-changed="(page) => emit('page-changed', page)"
|
||||
: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="!artist.channel && !isSerie">
|
||||
<h2>
|
||||
<translate translate-context="Content/*/Title/Noun">
|
||||
|
|
Loading…
Reference in New Issue