Fix play button in albums with multi-page volumes

environments/review-docs-renov-b1i8ag/deployments/15025
wvffle 2022-11-04 22:14:36 +00:00 zatwierdzone przez JuniorJPDJ
rodzic b7355c9c95
commit 2c9327fefc
3 zmienionych plików z 113 dodań i 70 usunięć

Wyświetl plik

@ -0,0 +1 @@
Fix play button in albums with multi-page volumes (#1928)

Wyświetl plik

@ -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>

Wyświetl plik

@ -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,67 +73,69 @@ 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">
<div
v-for="tracks in discs"
:key="getDiscKey(tracks)"
>
<div class="ui hidden divider" />
<play-button
class="right floated mini inverted vibrant"
:tracks="tracks"
/>
<translate
tag="h3"
:translate-params="{number: tracks[0].disc_number}"
translate-context="Content/Album/"
<template v-else>
<template v-if="discCount > 1">
<div
v-for="tracks, index in paginatedDiscs"
:key="index + getDiscKey(tracks)"
>
Volume %{ number }
</translate>
<template v-if="tracks.length > 0">
<div class="ui hidden divider" />
<play-button
class="right floated mini inverted vibrant"
:tracks="discs[index]"
/>
<translate
tag="h3"
:translate-params="{number: tracks[0]?.disc_number ?? index + 1}"
translate-context="Content/Album/"
>
Volume %{ number }
</translate>
<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="tracks"
:tracks="object.tracks"
:show-position="true"
:show-art="false"
:show-album="false"
:show-artist="false"
:paginate-results="false"
/>
</div>
</template>
<div
v-if="totalTracks > paginateBy"
class="ui center aligned basic segment tablet-and-below"
class="ui center aligned basic segment"
>
<pagination
:current="page"
v-model:current="page"
:paginate-by="paginateBy"
:total="totalTracks"
:compact="true"
@update:current="(page: number) => emit('page-changed', page)"
/>
</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="true"
:total="totalTracks"
:paginate-by="paginateBy"
:page="page"
@page-changed="(page) => emit('page-changed', page)"
/>
</template>
<template v-if="!artist.channel && !isSerie">
<h2>
<translate translate-context="Content/*/Title/Noun">