[web] Fix bug when adding playable items to queue

This commit is contained in:
Alain Nussbaumer 2025-02-13 21:02:13 +01:00
parent d6d5912de1
commit a93777aeec
33 changed files with 122 additions and 198 deletions

View File

@ -3,18 +3,14 @@
<div <div
class="media is-align-items-center is-clickable mb-0" class="media is-align-items-center is-clickable mb-0"
@click="open(item)" @click="open(item)"
>
<div
v-if="settingsStore.show_cover_artwork_in_album_lists"
class="media-left"
> >
<cover-artwork <cover-artwork
:url="artwork_url(item)" v-if="settingsStore.show_cover_artwork_in_album_lists"
:url="item.images?.[0]?.url ?? ''"
:artist="item.artist" :artist="item.artist"
:album="item.name" :album="item.name"
class="is-small" class="media-left is-small"
/> />
</div>
<div class="media-content"> <div class="media-content">
<div class="is-size-6 has-text-weight-bold" v-text="item.name" /> <div class="is-size-6 has-text-weight-bold" v-text="item.name" />
<div <div
@ -51,19 +47,13 @@ export default {
name: 'ListAlbumsSpotify', name: 'ListAlbumsSpotify',
components: { CoverArtwork, ModalDialogAlbumSpotify }, components: { CoverArtwork, ModalDialogAlbumSpotify },
props: { items: { required: true, type: Object } }, props: { items: { required: true, type: Object } },
setup() { setup() {
return { settingsStore: useSettingsStore() } return { settingsStore: useSettingsStore() }
}, },
data() { data() {
return { selected_item: {}, show_details_modal: false } return { selected_item: {}, show_details_modal: false }
}, },
methods: { methods: {
artwork_url(item) {
return item.images?.[0]?.url ?? ''
},
open(item) { open(item) {
this.$router.push({ this.$router.push({
name: 'music-spotify-album', name: 'music-spotify-album',

View File

@ -1,14 +1,12 @@
<template> <template>
<template v-for="item in items" :key="item.itemId"> <template v-for="item in items" :key="item.itemId">
<div v-if="!item.isItem" class="py-5"> <div v-if="!item.isItem" class="py-5">
<div class="media-content">
<span <span
:id="`index_${item.index}`" :id="`index_${item.index}`"
class="tag is-small has-text-weight-bold" class="tag is-small has-text-weight-bold"
v-text="item.index" v-text="item.index"
/> />
</div> </div>
</div>
<div <div
v-else v-else
class="media is-align-items-center is-clickable mb-0" class="media is-align-items-center is-clickable mb-0"
@ -39,15 +37,10 @@ import ModalDialogArtist from '@/components/ModalDialogArtist.vue'
export default { export default {
name: 'ListArtists', name: 'ListArtists',
components: { ModalDialogArtist }, components: { ModalDialogArtist },
props: { props: { items: { required: true, type: Object } },
items: { required: true, type: Object }
},
data() { data() {
return { return { selected_item: {}, show_details_modal: false }
selected_item: {},
show_details_modal: false
}
}, },
methods: { methods: {

View File

@ -39,15 +39,10 @@ import ModalDialogComposer from '@/components/ModalDialogComposer.vue'
export default { export default {
name: 'ListComposers', name: 'ListComposers',
components: { ModalDialogComposer }, components: { ModalDialogComposer },
props: { props: { items: { required: true, type: Object } },
items: { required: true, type: Object }
},
data() { data() {
return { return { selected_item: {}, show_details_modal: false }
selected_item: {},
show_details_modal: false
}
}, },
methods: { methods: {

View File

@ -54,10 +54,7 @@ export default {
props: { items: { required: true, type: Array } }, props: { items: { required: true, type: Array } },
data() { data() {
return { return { selected_item: '', show_details_modal: false }
selected_item: '',
show_details_modal: false
}
}, },
computed: { computed: {

View File

@ -45,10 +45,7 @@ export default {
media_kind: { required: true, type: String } media_kind: { required: true, type: String }
}, },
data() { data() {
return { return { selected_item: {}, show_details_modal: false }
selected_item: {},
show_details_modal: false
}
}, },
methods: { methods: {
open(item) { open(item) {

View File

@ -60,9 +60,7 @@ export default {
}, },
setup() { setup() {
return { return { playerStore: usePlayerStore() }
playerStore: usePlayerStore()
}
}, },
computed: { computed: {

View File

@ -33,10 +33,7 @@ export default {
props: { items: { required: true, type: Object } }, props: { items: { required: true, type: Object } },
data() { data() {
return { return { selected_item: {}, show_details_modal: false }
selected_item: {},
show_details_modal: false
}
}, },
methods: { methods: {

View File

@ -69,10 +69,7 @@ export default {
emits: ['play-count-changed'], emits: ['play-count-changed'],
data() { data() {
return { return { selected_item: {}, show_details_modal: false }
selected_item: {},
show_details_modal: false
}
}, },
methods: { methods: {

View File

@ -46,8 +46,7 @@ export default {
name: this.item.name, name: this.item.name,
handler: this.open, handler: this.open,
image: this.item.artwork_url, image: this.item.artwork_url,
artist: this.item.artist, uri: this.item.uri,
album: this.item.name,
properties: [ properties: [
{ {
label: 'property.artist', label: 'property.artist',

View File

@ -19,12 +19,11 @@ export default {
return { return {
name: this.item.name || '', name: this.item.name || '',
image: this.item?.images?.[0]?.url || '', image: this.item?.images?.[0]?.url || '',
artist: this.item.artist || '',
album: this.item.name || '',
handler: this.open, handler: this.open,
uri: this.item.uri,
properties: [ properties: [
{ {
label: 'property.album-artist', label: 'property.artist',
value: this.item?.artists?.[0]?.name, value: this.item?.artists?.[0]?.name,
handler: this.open_artist handler: this.open_artist
}, },

View File

@ -23,6 +23,7 @@ export default {
return { return {
name: this.item.name, name: this.item.name,
handler: this.open, handler: this.open,
uri: this.item.uri,
uris: this.uris, uris: this.uris,
properties: [ properties: [
{ label: 'property.tracks', value: this.item.item_count }, { label: 'property.tracks', value: this.item.item_count },

View File

@ -19,6 +19,7 @@ export default {
return { return {
name: this.item.name, name: this.item.name,
handler: this.open, handler: this.open,
uri: this.item.uri,
properties: [ properties: [
{ {
label: 'property.owner', label: 'property.owner',

View File

@ -44,6 +44,7 @@ export default {
playable() { playable() {
return { return {
name: this.item.title, name: this.item.title,
uri: this.item.uri,
properties: [ properties: [
{ {
label: 'property.album', label: 'property.album',

View File

@ -43,6 +43,7 @@ export default {
playable() { playable() {
return { return {
name: this.item.title, name: this.item.title,
uri: this.item.uri,
properties: [ properties: [
{ {
label: 'property.album', label: 'property.album',

View File

@ -16,9 +16,12 @@ export default {
emits: ['close'], emits: ['close'],
computed: { computed: {
playable() { playable() {
if (!this.item.artists) {
return {}
}
return { return {
name: this.item.name, name: this.item.name,
subtitle: this.item.artists[0].name, uri: this.item.uri,
properties: [ properties: [
{ {
label: 'property.album', label: 'property.album',
@ -27,20 +30,20 @@ export default {
}, },
{ {
label: 'property.album-artist', label: 'property.album-artist',
value: this.item.artists[0].name, value: this.item.artists[0]?.name,
handler: this.open_artist handler: this.open_artist
}, },
{ {
label: 'property.release-date', label: 'property.release-date',
value: this.$filters.date(item.album.release_date) value: this.$filters.date(this.item.album.release_date)
}, },
{ {
label: 'property.position', label: 'property.position',
value: [item.disc_number, item.track_number].join(' / ') value: [this.item.disc_number, this.item.track_number].join(' / ')
}, },
{ {
label: 'property.duration', label: 'property.duration',
value: this.$filters.durationInHours(item.duration_ms) value: this.$filters.durationInHours(this.item.duration_ms)
}, },
{ label: 'property.path', value: this.item.uri } { label: 'property.path', value: this.item.uri }
] ]

View File

@ -23,9 +23,7 @@ export default {
name: 'NotificationList', name: 'NotificationList',
setup() { setup() {
return { return { notificationsStore: useNotificationsStore() }
notificationsStore: useNotificationsStore()
}
}, },
computed: { computed: {

View File

@ -41,9 +41,7 @@ export default {
emits: ['search-library', 'search-spotify'], emits: ['search-library', 'search-spotify'],
setup() { setup() {
return { return { servicesStore: useServicesStore() }
servicesStore: useServicesStore()
}
}, },
computed: { computed: {

View File

@ -7,12 +7,12 @@
<a @click="open_artist" v-text="album.artists[0].name" /> <a @click="open_artist" v-text="album.artists[0].name" />
</div> </div>
<div class="buttons is-centered-mobile mt-5"> <div class="buttons is-centered-mobile mt-5">
<a class="button is-small is-dark is-rounded" @click="play"> <a class="button is-small is-rounded" @click="play">
<mdicon class="icon" name="shuffle" size="16" /> <mdicon class="icon" name="shuffle" size="16" />
<span v-text="$t('page.spotify.album.shuffle')" /> <span v-text="$t('page.spotify.album.shuffle')" />
</a> </a>
<a <a
class="button is-small is-light is-rounded" class="button is-small is-rounded"
@click="show_details_modal = true" @click="show_details_modal = true"
> >
<mdicon class="icon" name="dots-horizontal" size="16" /> <mdicon class="icon" name="dots-horizontal" size="16" />
@ -21,7 +21,7 @@
</template> </template>
<template #heading-right> <template #heading-right>
<cover-artwork <cover-artwork
:url="artwork_url(album)" :url="album.images?.[0]?.url ?? ''"
:artist="album.artists[0].name" :artist="album.artists[0].name"
:album="album.name" :album="album.name"
class="is-clickable is-medium" class="is-clickable is-medium"
@ -63,7 +63,6 @@ const dataObject = {
market: useServicesStore().spotify.webapi_country market: useServicesStore().spotify.webapi_country
}) })
}, },
set(vm, response) { set(vm, response) {
vm.album = response vm.album = response
} }
@ -77,26 +76,20 @@ export default {
ListTracksSpotify, ListTracksSpotify,
ModalDialogAlbumSpotify ModalDialogAlbumSpotify
}, },
beforeRouteEnter(to, from, next) { beforeRouteEnter(to, from, next) {
dataObject.load(to).then((response) => { dataObject.load(to).then((response) => {
next((vm) => dataObject.set(vm, response)) next((vm) => dataObject.set(vm, response))
}) })
}, },
setup() { setup() {
return { return { servicesStore: useServicesStore() }
servicesStore: useServicesStore()
}
}, },
data() { data() {
return { return {
album: { artists: [{}], tracks: {} }, album: { artists: [{}], tracks: {} },
show_details_modal: false show_details_modal: false
} }
}, },
computed: { computed: {
tracks() { tracks() {
const { album } = this const { album } = this
@ -107,9 +100,6 @@ export default {
} }
}, },
methods: { methods: {
artwork_url(album) {
return album.images?.[0]?.url ?? ''
},
open_artist() { open_artist() {
this.$router.push({ this.$router.push({
name: 'music-spotify-artist', name: 'music-spotify-artist',

View File

@ -48,12 +48,12 @@
<template #heading-right> <template #heading-right>
<div class="buttons is-centered"> <div class="buttons is-centered">
<a <a
class="button is-small is-light is-rounded" class="button is-small is-rounded"
@click="show_details_modal = true" @click="show_details_modal = true"
> >
<mdicon class="icon" name="dots-horizontal" size="16" /> <mdicon class="icon" name="dots-horizontal" size="16" />
</a> </a>
<a class="button is-small is-dark is-rounded" @click="play"> <a class="button is-small is-rounded" @click="play">
<mdicon class="icon" name="shuffle" size="16" /> <mdicon class="icon" name="shuffle" size="16" />
<span v-text="$t('page.artist.shuffle')" /> <span v-text="$t('page.artist.shuffle')" />
</a> </a>

View File

@ -11,12 +11,12 @@
<template #heading-right> <template #heading-right>
<div class="buttons is-centered"> <div class="buttons is-centered">
<a <a
class="button is-small is-light is-rounded" class="button is-small is-rounded"
@click="show_details_modal = true" @click="show_details_modal = true"
> >
<mdicon class="icon" name="dots-horizontal" size="16" /> <mdicon class="icon" name="dots-horizontal" size="16" />
</a> </a>
<a class="button is-small is-dark is-rounded" @click="play"> <a class="button is-small is-rounded" @click="play">
<mdicon class="icon" name="shuffle" size="16" /> <mdicon class="icon" name="shuffle" size="16" />
<span v-text="$t('page.spotify.artist.shuffle')" /> <span v-text="$t('page.spotify.artist.shuffle')" />
</a> </a>

View File

@ -49,12 +49,12 @@
<template #heading-right> <template #heading-right>
<div class="buttons is-centered"> <div class="buttons is-centered">
<a <a
class="button is-small is-light is-rounded" class="button is-small is-rounded"
@click="show_details_modal = true" @click="show_details_modal = true"
> >
<mdicon class="icon" name="dots-horizontal" size="16" /> <mdicon class="icon" name="dots-horizontal" size="16" />
</a> </a>
<a class="button is-small is-dark is-rounded" @click="play"> <a class="button is-small is-rounded" @click="play">
<mdicon class="icon" name="shuffle" size="16" /> <mdicon class="icon" name="shuffle" size="16" />
<span v-text="$t('page.artist.shuffle')" /> <span v-text="$t('page.artist.shuffle')" />
</a> </a>

View File

@ -7,12 +7,12 @@
<a @click="open_artist" v-text="album.artist" /> <a @click="open_artist" v-text="album.artist" />
</div> </div>
<div class="buttons is-centered-mobile mt-5"> <div class="buttons is-centered-mobile mt-5">
<a class="button is-small is-dark is-rounded" @click="play"> <a class="button is-small is-rounded" @click="play">
<mdicon class="icon" name="play" size="16" /> <mdicon class="icon" name="play" size="16" />
<span v-text="$t('page.audiobooks.album.play')" /> <span v-text="$t('page.audiobooks.album.play')" />
</a> </a>
<a <a
class="button is-small is-light is-rounded" class="button is-small is-rounded"
@click="show_details_modal = true" @click="show_details_modal = true"
> >
<mdicon class="icon" name="dots-horizontal" size="16" /> <mdicon class="icon" name="dots-horizontal" size="16" />

View File

@ -15,12 +15,12 @@
<template #heading-right> <template #heading-right>
<div class="buttons is-centered"> <div class="buttons is-centered">
<a <a
class="button is-small is-light is-rounded" class="button is-small is-rounded"
@click="show_details_modal = true" @click="show_details_modal = true"
> >
<mdicon class="icon" name="dots-horizontal" size="16" /> <mdicon class="icon" name="dots-horizontal" size="16" />
</a> </a>
<a class="button is-small is-dark is-rounded" @click="play"> <a class="button is-small is-rounded" @click="play">
<mdicon class="icon" name="play" size="16" /> <mdicon class="icon" name="play" size="16" />
<span v-text="$t('page.audiobooks.artist.play')" /> <span v-text="$t('page.audiobooks.artist.play')" />
</a> </a>
@ -52,7 +52,6 @@ const dataObject = {
webapi.library_artist_albums(to.params.id) webapi.library_artist_albums(to.params.id)
]) ])
}, },
set(vm, response) { set(vm, response) {
vm.artist = response[0].data vm.artist = response[0].data
vm.albums = new GroupedList(response[1].data) vm.albums = new GroupedList(response[1].data)
@ -62,13 +61,11 @@ const dataObject = {
export default { export default {
name: 'PageAudiobooksArtist', name: 'PageAudiobooksArtist',
components: { ContentWithHeading, ListAlbums, ModalDialogArtist }, components: { ContentWithHeading, ListAlbums, ModalDialogArtist },
beforeRouteEnter(to, from, next) { beforeRouteEnter(to, from, next) {
dataObject.load(to).then((response) => { dataObject.load(to).then((response) => {
next((vm) => dataObject.set(vm, response)) next((vm) => dataObject.set(vm, response))
}) })
}, },
data() { data() {
return { return {
albums: new GroupedList(), albums: new GroupedList(),
@ -76,7 +73,6 @@ export default {
show_details_modal: false show_details_modal: false
} }
}, },
methods: { methods: {
play() { play() {
webapi.player_play_uri( webapi.player_play_uri(

View File

@ -21,12 +21,12 @@
<template #heading-right> <template #heading-right>
<div class="buttons is-centered"> <div class="buttons is-centered">
<a <a
class="button is-small is-light is-rounded" class="button is-small is-rounded"
@click="show_details_modal = true" @click="show_details_modal = true"
> >
<mdicon class="icon" name="dots-horizontal" size="16" /> <mdicon class="icon" name="dots-horizontal" size="16" />
</a> </a>
<a class="button is-small is-dark is-rounded" @click="play"> <a class="button is-small is-rounded" @click="play">
<mdicon class="icon" name="shuffle" size="16" /> <mdicon class="icon" name="shuffle" size="16" />
<span v-text="$t('page.composer.shuffle')" /> <span v-text="$t('page.composer.shuffle')" />
</a> </a>
@ -72,13 +72,11 @@ export default {
ListAlbums, ListAlbums,
ModalDialogComposer ModalDialogComposer
}, },
beforeRouteEnter(to, from, next) { beforeRouteEnter(to, from, next) {
dataObject.load(to).then((response) => { dataObject.load(to).then((response) => {
next((vm) => dataObject.set(vm, response)) next((vm) => dataObject.set(vm, response))
}) })
}, },
data() { data() {
return { return {
albums: new GroupedList(), albums: new GroupedList(),
@ -86,7 +84,11 @@ export default {
show_details_modal: false show_details_modal: false
} }
}, },
computed: {
expression() {
return `composer is "${this.composer.name}" and media_kind is music`
}
},
methods: { methods: {
open_tracks() { open_tracks() {
this.$router.push({ this.$router.push({
@ -95,10 +97,7 @@ export default {
}) })
}, },
play() { play() {
webapi.player_play_expression( webapi.player_play_expression(this.expression, true)
`composer is "${this.composer.name}" and media_kind is music`,
true
)
} }
} }
} }

View File

@ -38,12 +38,12 @@
<template #heading-right> <template #heading-right>
<div class="buttons is-centered"> <div class="buttons is-centered">
<a <a
class="button is-small is-light is-rounded" class="button is-small is-rounded"
@click="show_details_modal = true" @click="show_details_modal = true"
> >
<mdicon class="icon" name="dots-horizontal" size="16" /> <mdicon class="icon" name="dots-horizontal" size="16" />
</a> </a>
<a class="button is-small is-dark is-rounded" @click="play"> <a class="button is-small is-rounded" @click="play">
<mdicon class="icon" name="shuffle" size="16" /> <mdicon class="icon" name="shuffle" size="16" />
<span v-text="$t('page.composer.shuffle')" /> <span v-text="$t('page.composer.shuffle')" />
</a> </a>
@ -94,17 +94,14 @@ export default {
ListTracks, ListTracks,
ModalDialogComposer ModalDialogComposer
}, },
beforeRouteEnter(to, from, next) { beforeRouteEnter(to, from, next) {
dataObject.load(to).then((response) => { dataObject.load(to).then((response) => {
next((vm) => dataObject.set(vm, response)) next((vm) => dataObject.set(vm, response))
}) })
}, },
setup() { setup() {
return { uiStore: useUIStore() } return { uiStore: useUIStore() }
}, },
data() { data() {
return { return {
composer: {}, composer: {},
@ -127,7 +124,6 @@ export default {
tracks_list: new GroupedList() tracks_list: new GroupedList()
} }
}, },
computed: { computed: {
expression() { expression() {
return `composer is "${this.composer.name}" and media_kind is music` return `composer is "${this.composer.name}" and media_kind is music`
@ -139,10 +135,8 @@ export default {
return this.tracks_list.group(options) return this.tracks_list.group(options)
} }
}, },
methods: { methods: {
open_albums() { open_albums() {
this.show_details_modal = false
this.$router.push({ this.$router.push({
name: 'music-composer-albums', name: 'music-composer-albums',
params: { name: this.composer.name } params: { name: this.composer.name }

View File

@ -7,12 +7,12 @@
<template #heading-right> <template #heading-right>
<div class="buttons is-centered"> <div class="buttons is-centered">
<a <a
class="button is-small is-light is-rounded" class="button is-small is-rounded"
@click="show_details_modal = true" @click="show_details_modal = true"
> >
<mdicon class="icon" name="dots-horizontal" size="16" /> <mdicon class="icon" name="dots-horizontal" size="16" />
</a> </a>
<a class="button is-small is-dark is-rounded" @click="play"> <a class="button is-small is-rounded" @click="play">
<mdicon class="icon" name="play" size="16" /> <mdicon class="icon" name="play" size="16" />
<span v-text="$t('page.files.play')" /> <span v-text="$t('page.files.play')" />
</a> </a>
@ -22,7 +22,7 @@
<list-directories :items="directories" /> <list-directories :items="directories" />
<list-playlists :items="playlists" /> <list-playlists :items="playlists" />
<list-tracks <list-tracks
:expression="play_expression" :expression="expression"
:items="tracks" :items="tracks"
:show_icon="true" :show_icon="true"
/> />
@ -83,26 +83,22 @@ export default {
ListTracks, ListTracks,
ModalDialogDirectory ModalDialogDirectory
}, },
beforeRouteEnter(to, from, next) { beforeRouteEnter(to, from, next) {
dataObject.load(to).then((response) => { dataObject.load(to).then((response) => {
next((vm) => dataObject.set(vm, response)) next((vm) => dataObject.set(vm, response))
}) })
}, },
beforeRouteUpdate(to, from, next) { beforeRouteUpdate(to, from, next) {
dataObject.load(to).then((response) => { dataObject.load(to).then((response) => {
dataObject.set(this, response) dataObject.set(this, response)
next() next()
}) })
}, },
setup() { setup() {
return { return {
configurationStore: useConfigurationStore() configurationStore: useConfigurationStore()
} }
}, },
data() { data() {
return { return {
directories: [], directories: [],
@ -111,7 +107,6 @@ export default {
tracks: new GroupedList() tracks: new GroupedList()
} }
}, },
computed: { computed: {
current() { current() {
return this.$route.query?.directory || '/' return this.$route.query?.directory || '/'
@ -122,14 +117,13 @@ export default {
} }
return this.$t('page.files.title') return this.$t('page.files.title')
}, },
play_expression() { expression() {
return `path starts with "${this.current}" order by path asc` return `path starts with "${this.current}" order by path asc`
} }
}, },
methods: { methods: {
play() { play() {
webapi.player_play_expression(this.play_expression, false) webapi.player_play_expression(this.expression, false)
}, },
transform(path) { transform(path) {
return { name: path.slice(path.lastIndexOf('/') + 1), path } return { name: path.slice(path.lastIndexOf('/') + 1), path }

View File

@ -20,12 +20,12 @@
<template #heading-right> <template #heading-right>
<div class="buttons is-centered"> <div class="buttons is-centered">
<a <a
class="button is-small is-light is-rounded" class="button is-small is-rounded"
@click="show_details_modal = true" @click="show_details_modal = true"
> >
<mdicon class="icon" name="dots-horizontal" size="16" /> <mdicon class="icon" name="dots-horizontal" size="16" />
</a> </a>
<a class="button is-small is-dark is-rounded" @click="play"> <a class="button is-small is-rounded" @click="play">
<mdicon class="icon" name="shuffle" size="16" /> <mdicon class="icon" name="shuffle" size="16" />
<span v-text="$t('page.genre.shuffle')" /> <span v-text="$t('page.genre.shuffle')" />
</a> </a>
@ -59,7 +59,6 @@ const dataObject = {
webapi.library_genre_albums(to.params.name, to.query.media_kind) webapi.library_genre_albums(to.params.name, to.query.media_kind)
]) ])
}, },
set(vm, response) { set(vm, response) {
vm.genre = response[0].data.genres.items.shift() vm.genre = response[0].data.genres.items.shift()
vm.albums = new GroupedList(response[1].data.albums, { vm.albums = new GroupedList(response[1].data.albums, {
@ -81,7 +80,6 @@ export default {
next((vm) => dataObject.set(vm, response)) next((vm) => dataObject.set(vm, response))
}) })
}, },
data() { data() {
return { return {
albums: new GroupedList(), albums: new GroupedList(),

View File

@ -32,12 +32,12 @@
<template #heading-right> <template #heading-right>
<div class="buttons is-centered"> <div class="buttons is-centered">
<a <a
class="button is-small is-light is-rounded" class="button is-small is-rounded"
@click="show_details_modal = true" @click="show_details_modal = true"
> >
<mdicon class="icon" name="dots-horizontal" size="16" /> <mdicon class="icon" name="dots-horizontal" size="16" />
</a> </a>
<a class="button is-small is-dark is-rounded" @click="play"> <a class="button is-small is-rounded" @click="play">
<mdicon class="icon" name="shuffle" size="16" /> <mdicon class="icon" name="shuffle" size="16" />
<span v-text="$t('page.genre.shuffle')" /> <span v-text="$t('page.genre.shuffle')" />
</a> </a>
@ -89,17 +89,14 @@ export default {
ListTracks, ListTracks,
ModalDialogGenre ModalDialogGenre
}, },
beforeRouteEnter(to, from, next) { beforeRouteEnter(to, from, next) {
dataObject.load(to).then((response) => { dataObject.load(to).then((response) => {
next((vm) => dataObject.set(vm, response)) next((vm) => dataObject.set(vm, response))
}) })
}, },
setup() { setup() {
return { uiStore: useUIStore() } return { uiStore: useUIStore() }
}, },
data() { data() {
return { return {
genre: {}, genre: {},
@ -123,7 +120,6 @@ export default {
tracks_list: new GroupedList() tracks_list: new GroupedList()
} }
}, },
computed: { computed: {
expression() { expression() {
return `genre is "${this.genre.name}" and media_kind is ${this.media_kind}` return `genre is "${this.genre.name}" and media_kind is ${this.media_kind}`
@ -135,7 +131,6 @@ export default {
return this.tracks_list.group(options) return this.tracks_list.group(options)
} }
}, },
methods: { methods: {
open_genre() { open_genre() {
this.show_details_modal = false this.show_details_modal = false

View File

@ -11,12 +11,12 @@
<template #heading-right> <template #heading-right>
<div class="buttons is-centered"> <div class="buttons is-centered">
<a <a
class="button is-small is-light is-rounded" class="button is-small is-rounded"
@click="show_details_modal = true" @click="show_details_modal = true"
> >
<mdicon class="icon" name="dots-horizontal" size="16" /> <mdicon class="icon" name="dots-horizontal" size="16" />
</a> </a>
<a class="button is-small is-dark is-rounded" @click="play"> <a class="button is-small is-rounded" @click="play">
<mdicon class="icon" name="shuffle" size="16" /> <mdicon class="icon" name="shuffle" size="16" />
<span v-text="$t('page.playlist.shuffle')" /> <span v-text="$t('page.playlist.shuffle')" />
</a> </a>

View File

@ -13,12 +13,12 @@
<template #heading-right> <template #heading-right>
<div class="buttons is-centered"> <div class="buttons is-centered">
<a <a
class="button is-small is-light is-rounded" class="button is-small is-rounded"
@click="show_playlist_details_modal = true" @click="show_playlist_details_modal = true"
> >
<mdicon class="icon" name="dots-horizontal" size="16" /> <mdicon class="icon" name="dots-horizontal" size="16" />
</a> </a>
<a class="button is-small is-dark is-rounded" @click="play"> <a class="button is-small is-rounded" @click="play">
<mdicon class="icon" name="shuffle" size="16" /> <mdicon class="icon" name="shuffle" size="16" />
<span v-text="$t('page.spotify.playlist.shuffle')" /> <span v-text="$t('page.spotify.playlist.shuffle')" />
</a> </a>

View File

@ -7,12 +7,12 @@
<br /> <br />
</div> </div>
<div class="buttons is-centered-mobile mt-5"> <div class="buttons is-centered-mobile mt-5">
<a class="button is-small is-dark is-rounded" @click="play"> <a class="button is-small is-rounded" @click="play">
<mdicon class="icon" name="play" size="16" /> <mdicon class="icon" name="play" size="16" />
<span v-text="$t('page.podcast.play')" /> <span v-text="$t('page.podcast.play')" />
</a> </a>
<a <a
class="button is-small is-light is-rounded" class="button is-small is-rounded"
@click="show_details_modal = true" @click="show_details_modal = true"
> >
<mdicon class="icon" name="dots-horizontal" size="16" /> <mdicon class="icon" name="dots-horizontal" size="16" />

View File

@ -22,7 +22,7 @@
<p v-text="$t('page.settings.services.spotify.requirements')" /> <p v-text="$t('page.settings.services.spotify.requirements')" />
<p v-text="spotify_required_scope.join(', ')" /> <p v-text="spotify_required_scope.join(', ')" />
</div> </div>
<p v-if="spotify.webapi_token_valid"> <p v-if="spotify.webapi_token_valid" class="content">
<span v-text="$t('page.settings.services.spotify.user')" /> <span v-text="$t('page.settings.services.spotify.user')" />
<code v-text="spotify.webapi_user" /> <code v-text="spotify.webapi_user" />
</p> </p>

View File

@ -315,53 +315,50 @@ export default {
return axios.get('./api/queue') return axios.get('./api/queue')
}, },
queue_add(uri) { async queue_add(uri) {
return axios.post(`./api/queue/items/add?uris=${uri}`).then((response) => { const response = await axios.post(`./api/queue/items/add?uris=${uri}`)
useNotificationsStore().add({ useNotificationsStore().add({
text: t('server.appended-tracks', { count: response.data.count }), text: t('server.appended-tracks', { count: response.data.count }),
timeout: 2000, timeout: 2000,
type: 'info' type: 'info'
}) })
return Promise.resolve(response) return await Promise.resolve(response)
})
}, },
queue_add_next(uri) { async queue_add_next(uri) {
let position = 0 let position = 0
const { current } = useQueueStore() const { current } = useQueueStore()
if (current?.id) { if (current?.id) {
position = current.position + 1 position = current.position + 1
} }
return axios const response = await axios.post(
.post(`./api/queue/items/add?uris=${uri}&position=${position}`) `./api/queue/items/add?uris=${uri}&position=${position}`
.then((response) => { )
useNotificationsStore().add({ useNotificationsStore().add({
text: t('server.appended-tracks', { count: response.data.count }), text: t('server.appended-tracks', { count: response.data.count }),
timeout: 2000, timeout: 2000,
type: 'info' type: 'info'
}) })
return Promise.resolve(response) return await Promise.resolve(response)
})
}, },
queue_clear() { queue_clear() {
return axios.put('./api/queue/clear') return axios.put('./api/queue/clear')
}, },
queue_expression_add(expression) { async queue_expression_add(expression) {
return axios const response = await axios.post('./api/queue/items/add', null, {
.post('./api/queue/items/add', null, { params: { expression } }) params: { expression }
.then((response) => { })
useNotificationsStore().add({ useNotificationsStore().add({
text: t('server.appended-tracks', { count: response.data.count }), text: t('server.appended-tracks', { count: response.data.count }),
timeout: 2000, timeout: 2000,
type: 'info' type: 'info'
}) })
return Promise.resolve(response) return await Promise.resolve(response)
})
}, },
queue_expression_add_next(expression) { async queue_expression_add_next(expression) {
const params = {} const params = {}
params.expression = expression params.expression = expression
params.position = 0 params.position = 0
@ -369,16 +366,13 @@ export default {
if (current?.id) { if (current?.id) {
params.position = current.position + 1 params.position = current.position + 1
} }
return axios const response = await axios.post('./api/queue/items/add', null, { params })
.post('./api/queue/items/add', null, { params })
.then((response) => {
useNotificationsStore().add({ useNotificationsStore().add({
text: t('server.appended-tracks', { count: response.data.count }), text: t('server.appended-tracks', { count: response.data.count }),
timeout: 2000, timeout: 2000,
type: 'info' type: 'info'
}) })
return Promise.resolve(response) return await Promise.resolve(response)
})
}, },
queue_move(itemId, position) { queue_move(itemId, position) {
@ -389,17 +383,16 @@ export default {
return axios.delete(`./api/queue/items/${itemId}`) return axios.delete(`./api/queue/items/${itemId}`)
}, },
queue_save_playlist(name) { async queue_save_playlist(name) {
return axios const response = await axios.post('./api/queue/save', null, {
.post('./api/queue/save', null, { params: { name } }) params: { name }
.then((response) => { })
useNotificationsStore().add({ useNotificationsStore().add({
text: t('server.queue-saved', { name }), text: t('server.queue-saved', { name }),
timeout: 2000, timeout: 2000,
type: 'info' type: 'info'
}) })
return Promise.resolve(response) return await Promise.resolve(response)
})
}, },
search(params) { search(params) {