[web] Change to camel case.

This commit is contained in:
Alain Nussbaumer 2025-03-11 19:42:17 +01:00
parent 905d0ca88b
commit da30c338fc
62 changed files with 522 additions and 647 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -9,15 +9,15 @@
@close="pairing_active = false" @close="pairing_active = false"
/> />
<modal-dialog-update <modal-dialog-update
:show="show_update_dialog" :show="showUpdateDialog"
@close="show_update_dialog = false" @close="showUpdateDialog = false"
/> />
<notification-list v-show="!show_burger_menu" /> <notification-list v-show="!showBurgerMenu" />
<navbar-bottom /> <navbar-bottom />
<div <div
v-show="show_burger_menu || show_player_menu" v-show="showBurgerMenu || showPlayerMenu"
class="overlay-fullscreen" class="overlay-fullscreen"
@click="show_burger_menu = show_player_menu = false" @click="uiStore.hideMenus"
/> />
</template> </template>
@ -50,7 +50,6 @@ export default {
NavbarTop, NavbarTop,
NotificationList NotificationList
}, },
setup() { setup() {
return { return {
configurationStore: useConfigurationStore(), configurationStore: useConfigurationStore(),
@ -66,7 +65,6 @@ export default {
uiStore: useUIStore() uiStore: useUIStore()
} }
}, },
data() { data() {
return { return {
pairing_active: false, pairing_active: false,
@ -74,50 +72,47 @@ export default {
token_timer_id: 0 token_timer_id: 0
} }
}, },
computed: { computed: {
show_burger_menu: { showBurgerMenu: {
get() { get() {
return this.uiStore.show_burger_menu return this.uiStore.showBurgerMenu
}, },
set(value) { set(value) {
this.uiStore.show_burger_menu = value this.uiStore.showBurgerMenu = value
} }
}, },
show_player_menu: { showPlayerMenu: {
get() { get() {
return this.uiStore.show_player_menu return this.uiStore.showPlayerMenu
}, },
set(value) { set(value) {
this.uiStore.show_player_menu = value this.uiStore.showPlayerMenu = value
} }
}, },
show_update_dialog: { showUpdateDialog: {
get() { get() {
return this.uiStore.show_update_dialog return this.uiStore.showUpdateDialog
}, },
set(value) { set(value) {
this.uiStore.show_update_dialog = value this.uiStore.showUpdateDialog = value
} }
} }
}, },
watch: { watch: {
show_burger_menu() { showBurgerMenu() {
this.update_is_clipped() this.update_is_clipped()
}, },
show_player_menu() { showPlayerMenu() {
this.update_is_clipped() this.update_is_clipped()
} }
}, },
created() { created() {
this.connect() this.connect()
// Start the progress bar on app start // Start the progress bar on app start
this.$Progress.start() this.$Progress.start()
// Hook the progress bar to start before we move router-view // Hook the progress bar to start before we move router-view
this.$router.beforeEach((to, from, next) => { this.$router.beforeEach((to, from, next) => {
if (to.meta.show_progress && !(to.path === from.path && to.hash)) { if (!(to.path === from.path && to.hash)) {
if (to.meta.progress) { if (to.meta.progress) {
this.$Progress.parseMeta(to.meta.progress) this.$Progress.parseMeta(to.meta.progress)
} }
@ -127,19 +122,16 @@ export default {
}) })
// Hook the progress bar to finish after we've finished moving router-view // Hook the progress bar to finish after we've finished moving router-view
this.$router.afterEach((to, from) => { this.$router.afterEach((to, from) => {
if (to.meta.show_progress) { this.$Progress.finish()
this.$Progress.finish()
}
}) })
}, },
methods: { methods: {
connect() { connect() {
webapi webapi
.config() .config()
.then(({ data }) => { .then(({ data }) => {
this.configurationStore.$state = data this.configurationStore.$state = data
this.uiStore.hide_singles = data.hide_singles this.uiStore.hideSingles = data.hide_singles
document.title = data.library_name document.title = data.library_name
this.openWebsocket() this.openWebsocket()
this.$Progress.finish() this.$Progress.finish()
@ -267,7 +259,7 @@ export default {
}) })
}, },
update_is_clipped() { update_is_clipped() {
if (this.show_burger_menu || this.show_player_menu) { if (this.showBurgerMenu || this.showPlayerMenu) {
document.querySelector('html').classList.add('is-clipped') document.querySelector('html').classList.add('is-clipped')
} else { } else {
document.querySelector('html').classList.remove('is-clipped') document.querySelector('html').classList.remove('is-clipped')

View File

@ -17,8 +17,7 @@ export default {
}, },
methods: { methods: {
open() { open() {
this.uiStore.show_burger_menu = false this.uiStore.hideMenus()
this.uiStore.show_player_menu = false
this.$router.push(this.to) this.$router.push(this.to)
} }
} }

View File

@ -18,36 +18,26 @@ export default {
props: { props: {
offset: { required: true, type: Number } offset: { required: true, type: Number }
}, },
setup() { setup() {
return { return {
playerStore: usePlayerStore(), playerStore: usePlayerStore(),
queueStore: useQueueStore() queueStore: useQueueStore()
} }
}, },
computed: { computed: {
disabled() { disabled() {
return ( return (
this.queueStore?.count <= 0 || this.queueStore?.count <= 0 ||
this.is_stopped || this.playerStore.isStopped ||
this.current.data_kind === 'pipe' this.queueStore.current.data_kind === 'pipe'
) )
}, },
is_stopped() {
return this.player.state === 'stop'
},
current() {
return this.queueStore.current
},
player() {
return this.playerStore
},
visible() { visible() {
return ['podcast', 'audiobook'].includes(this.current.media_kind) return ['podcast', 'audiobook'].includes(
this.queueStore.current.media_kind
)
} }
}, },
methods: { methods: {
seek() { seek() {
if (!this.disabled) { if (!this.disabled) {

View File

@ -1,5 +1,5 @@
<template> <template>
<a :class="{ 'is-dark': is_consume }" @click="toggle"> <a :class="{ 'is-dark': playerStore.consume }" @click="toggle">
<mdicon <mdicon
class="icon" class="icon"
name="fire" name="fire"
@ -15,22 +15,14 @@ import webapi from '@/webapi'
export default { export default {
name: 'ControlPlayerConsume', name: 'ControlPlayerConsume',
setup() { setup() {
return { return {
playerStore: usePlayerStore() playerStore: usePlayerStore()
} }
}, },
computed: {
is_consume() {
return this.playerStore.consume
}
},
methods: { methods: {
toggle() { toggle() {
webapi.player_consume(!this.is_consume) webapi.player_consume(!this.playerStore.consume)
} }
} }
} }

View File

@ -25,24 +25,17 @@ export default {
} }
}, },
computed: { computed: {
current() {
return this.queueStore.current
},
disabled() { disabled() {
return ( return (
this.queueStore?.count <= 0 || this.queueStore?.count <= 0 ||
this.is_stopped || this.playerStore.isStopped ||
this.current.data_kind === 'pipe' this.queueStore.current.data_kind === 'pipe'
) )
}, },
is_stopped() {
return this.player.state === 'stop'
},
player() {
return this.playerStore
},
visible() { visible() {
return ['podcast', 'audiobook'].includes(this.current.media_kind) return ['podcast', 'audiobook'].includes(
this.queueStore.current.media_kind
)
} }
}, },
methods: { methods: {

View File

@ -1,5 +1,5 @@
<template> <template>
<a :class="{ 'is-dark': isActive }" @click="toggle"> <a :class="{ 'is-dark': lyricsStore.active }" @click="lyricsStore.toggle">
<mdicon <mdicon
class="icon" class="icon"
:name="icon" :name="icon"
@ -21,15 +21,9 @@ export default {
}, },
computed: { computed: {
icon() { icon() {
return this.isActive ? 'script-text-play' : 'script-text-outline' return this.lyricsStore.active
}, ? 'script-text-play'
isActive() { : 'script-text-outline'
return this.lyricsStore.pane
}
},
methods: {
toggle() {
this.lyricsStore.pane = !this.lyricsStore.pane
} }
} }
} }

View File

@ -1,5 +1,5 @@
<template> <template>
<a :disabled="disabled" @click="play_next"> <a :disabled="disabled" @click="next">
<mdicon <mdicon
class="icon" class="icon"
name="skip-forward" name="skip-forward"
@ -14,15 +14,16 @@ import webapi from '@/webapi'
export default { export default {
name: 'ControlPlayerNext', name: 'ControlPlayerNext',
setup() {
return { queueStore: useQueueStore() }
},
computed: { computed: {
disabled() { disabled() {
return useQueueStore()?.count <= 0 return this.queueStore.count <= 0
} }
}, },
methods: { methods: {
play_next() { next() {
if (this.disabled) { if (this.disabled) {
return return
} }

View File

@ -27,19 +27,12 @@ export default {
return this.queueStore?.count <= 0 return this.queueStore?.count <= 0
}, },
icon() { icon() {
if (!this.is_playing) { if (!this.playerStore.isPlaying) {
return 'play' return 'play'
} else if (this.is_pause_allowed) { } else if (this.queueStore.isPauseAllowed) {
return 'pause' return 'pause'
} }
return 'stop' return 'stop'
},
is_pause_allowed() {
const { current } = this.queueStore
return current && current.data_kind !== 'pipe'
},
is_playing() {
return this.playerStore.state === 'play'
} }
}, },
methods: { methods: {
@ -55,9 +48,12 @@ export default {
} }
return return
} }
if (this.is_playing && this.is_pause_allowed) { if (this.playerStore.isPlaying && this.queueStore.isPauseAllowed) {
webapi.player_pause() webapi.player_pause()
} else if (this.is_playing && !this.is_pause_allowed) { } else if (
this.playerStore.isPlaying &&
!this.queueStore.isPauseAllowed
) {
webapi.player_stop() webapi.player_stop()
} else { } else {
webapi.player_play() webapi.player_play()

View File

@ -15,9 +15,7 @@ import webapi from '@/webapi'
export default { export default {
name: 'ControlPlayerPrevious', name: 'ControlPlayerPrevious',
setup() { setup() {
return { return { queueStore: useQueueStore() }
queueStore: useQueueStore()
}
}, },
computed: { computed: {
disabled() { disabled() {

View File

@ -1,5 +1,5 @@
<template> <template>
<a :class="{ 'is-dark': !is_repeat_off }" @click="toggle"> <a :class="{ 'is-dark': !playerStore.isRepeatOff }" @click="toggle">
<mdicon <mdicon
class="icon" class="icon"
:name="icon" :name="icon"
@ -16,35 +16,23 @@ import webapi from '@/webapi'
export default { export default {
name: 'ControlPlayerRepeat', name: 'ControlPlayerRepeat',
setup() { setup() {
return { return { playerStore: usePlayerStore() }
playerStore: usePlayerStore()
}
}, },
computed: { computed: {
icon() { icon() {
if (this.is_repeat_all) { if (this.playerStore.isRepeatAll) {
return 'repeat' return 'repeat'
} else if (this.is_repeat_single) { } else if (this.playerStore.isRepeatSingle) {
return 'repeat-once' return 'repeat-once'
} }
return 'repeat-off' return 'repeat-off'
},
is_repeat_all() {
return this.playerStore.repeat === 'all'
},
is_repeat_off() {
return !this.is_repeat_all && !this.is_repeat_single
},
is_repeat_single() {
return this.playerStore.repeat === 'single'
} }
}, },
methods: { methods: {
toggle() { toggle() {
if (this.is_repeat_all) { if (this.playerStore.isRepeatAll) {
webapi.player_repeat('single') webapi.player_repeat('single')
} else if (this.is_repeat_single) { } else if (this.playerStore.isRepeatSingle) {
webapi.player_repeat('off') webapi.player_repeat('off')
} else { } else {
webapi.player_repeat('all') webapi.player_repeat('all')

View File

@ -1,5 +1,5 @@
<template> <template>
<a :class="{ 'is-dark': isShuffle }" @click="toggle"> <a :class="{ 'is-dark': playerStore.shuffle }" @click="toggle">
<mdicon <mdicon
class="icon" class="icon"
:name="icon" :name="icon"
@ -16,24 +16,19 @@ import webapi from '@/webapi'
export default { export default {
name: 'ControlPlayerShuffle', name: 'ControlPlayerShuffle',
setup() { setup() {
return { return { playerStore: usePlayerStore() }
playerStore: usePlayerStore()
}
}, },
computed: { computed: {
icon() { icon() {
if (this.isShuffle) { if (this.playerStore.shuffle) {
return 'shuffle' return 'shuffle'
} }
return 'shuffle-disabled' return 'shuffle-disabled'
},
isShuffle() {
return this.playerStore.shuffle
} }
}, },
methods: { methods: {
toggle() { toggle() {
webapi.player_shuffle(!this.is_shuffle) webapi.player_shuffle(!this.playerStore.shuffle)
} }
} }
} }

View File

@ -40,18 +40,18 @@
</template> </template>
<teleport to="#app"> <teleport to="#app">
<modal-dialog-album <modal-dialog-album
:item="selected_item" :item="selectedItem"
:media_kind="media_kind" :media_kind="media_kind"
:show="show_details_modal" :show="showDetailsModal"
@close="show_details_modal = false" @close="showDetailsModal = false"
@remove-podcast="openRemovePodcastDialog()" @remove-podcast="openRemovePodcastDialog()"
@play-count-changed="onPlayCountChange()" @play-count-changed="onPlayCountChange()"
/> />
<modal-dialog <modal-dialog
:actions="actions" :actions="actions"
:show="show_remove_podcast_modal" :show="showRemovePodcastModal"
:title="$t('page.podcast.remove-podcast')" :title="$t('page.podcast.remove-podcast')"
@cancel="show_remove_podcast_modal = false" @cancel="showRemovePodcastModal = false"
@remove="removePodcast" @remove="removePodcast"
> >
<template #content> <template #content>
@ -89,9 +89,9 @@ export default {
data() { data() {
return { return {
rss_playlist_to_remove: {}, rss_playlist_to_remove: {},
selected_item: {}, selectedItem: {},
show_details_modal: false, showDetailsModal: false,
show_remove_podcast_modal: false showRemovePodcastModal: false
} }
}, },
computed: { computed: {
@ -102,12 +102,12 @@ export default {
] ]
}, },
media_kind_resolved() { media_kind_resolved() {
return this.media_kind || this.selected_item.media_kind return this.media_kind || this.selectedItem.media_kind
} }
}, },
methods: { methods: {
open(item) { open(item) {
this.selected_item = item this.selectedItem = item
if (this.media_kind_resolved === 'podcast') { if (this.media_kind_resolved === 'podcast') {
this.$router.push({ name: 'podcast', params: { id: item.id } }) this.$router.push({ name: 'podcast', params: { id: item.id } })
} else if (this.media_kind_resolved === 'audiobook') { } else if (this.media_kind_resolved === 'audiobook') {
@ -120,19 +120,19 @@ export default {
} }
}, },
openDialog(item) { openDialog(item) {
this.selected_item = item this.selectedItem = item
this.show_details_modal = true this.showDetailsModal = true
}, },
openRemovePodcastDialog() { openRemovePodcastDialog() {
webapi webapi
.library_album_tracks(this.selected_item.id, { limit: 1 }) .library_album_tracks(this.selectedItem.id, { limit: 1 })
.then(({ data: album }) => { .then(({ data: album }) => {
webapi.library_track_playlists(album.items[0].id).then(({ data }) => { webapi.library_track_playlists(album.items[0].id).then(({ data }) => {
;[this.rss_playlist_to_remove] = data.items.filter( ;[this.rss_playlist_to_remove] = data.items.filter(
(playlist) => playlist.type === 'rss' (playlist) => playlist.type === 'rss'
) )
this.show_remove_podcast_modal = true this.showRemovePodcastModal = true
this.show_details_modal = false this.showDetailsModal = false
}) })
}) })
}, },
@ -140,7 +140,7 @@ export default {
this.$emit('play-count-changed') this.$emit('play-count-changed')
}, },
removePodcast() { removePodcast() {
this.show_remove_podcast_modal = false this.showRemovePodcastModal = false
webapi webapi
.library_playlist_delete(this.rss_playlist_to_remove.id) .library_playlist_delete(this.rss_playlist_to_remove.id)
.then(() => { .then(() => {

View File

@ -31,9 +31,9 @@
</template> </template>
<teleport to="#app"> <teleport to="#app">
<modal-dialog-album-spotify <modal-dialog-album-spotify
:item="selected_item" :item="selectedItem"
:show="show_details_modal" :show="showDetailsModal"
@close="show_details_modal = false" @close="showDetailsModal = false"
/> />
</teleport> </teleport>
</template> </template>
@ -51,7 +51,7 @@ export default {
return { settingsStore: useSettingsStore() } return { settingsStore: useSettingsStore() }
}, },
data() { data() {
return { selected_item: {}, show_details_modal: false } return { selectedItem: {}, showDetailsModal: false }
}, },
methods: { methods: {
open(item) { open(item) {
@ -61,8 +61,8 @@ export default {
}) })
}, },
openDialog(item) { openDialog(item) {
this.selected_item = item this.selectedItem = item
this.show_details_modal = true this.showDetailsModal = true
} }
} }
} }

View File

@ -24,9 +24,9 @@
</template> </template>
<teleport to="#app"> <teleport to="#app">
<modal-dialog-artist <modal-dialog-artist
:item="selected_item" :item="selectedItem"
:show="show_details_modal" :show="showDetailsModal"
@close="show_details_modal = false" @close="showDetailsModal = false"
/> />
</teleport> </teleport>
</template> </template>
@ -40,19 +40,19 @@ export default {
props: { items: { required: true, type: Object } }, props: { items: { required: true, type: Object } },
data() { data() {
return { selected_item: {}, show_details_modal: false } return { selectedItem: {}, showDetailsModal: false }
}, },
methods: { methods: {
open(item) { open(item) {
this.selected_item = item this.selectedItem = item
const route = const route =
item.media_kind === 'audiobook' ? 'audiobooks-artist' : 'music-artist' item.media_kind === 'audiobook' ? 'audiobooks-artist' : 'music-artist'
this.$router.push({ name: route, params: { id: item.id } }) this.$router.push({ name: route, params: { id: item.id } })
}, },
openDialog(item) { openDialog(item) {
this.selected_item = item this.selectedItem = item
this.show_details_modal = true this.showDetailsModal = true
} }
} }
} }

View File

@ -13,9 +13,9 @@
</template> </template>
<teleport to="#app"> <teleport to="#app">
<modal-dialog-artist-spotify <modal-dialog-artist-spotify
:item="selected_item" :item="selectedItem"
:show="show_details_modal" :show="showDetailsModal"
@close="show_details_modal = false" @close="showDetailsModal = false"
/> />
</teleport> </teleport>
</template> </template>
@ -29,7 +29,7 @@ export default {
props: { items: { required: true, type: Object } }, props: { items: { required: true, type: Object } },
data() { data() {
return { selected_item: {}, show_details_modal: false } return { selectedItem: {}, showDetailsModal: false }
}, },
methods: { methods: {
open(item) { open(item) {
@ -39,8 +39,8 @@ export default {
}) })
}, },
openDialog(item) { openDialog(item) {
this.selected_item = item this.selectedItem = item
this.show_details_modal = true this.showDetailsModal = true
} }
} }
} }

View File

@ -26,9 +26,9 @@
</template> </template>
<teleport to="#app"> <teleport to="#app">
<modal-dialog-composer <modal-dialog-composer
:item="selected_item" :item="selectedItem"
:show="show_details_modal" :show="showDetailsModal"
@close="show_details_modal = false" @close="showDetailsModal = false"
/> />
</teleport> </teleport>
</template> </template>
@ -42,12 +42,12 @@ export default {
props: { items: { required: true, type: Object } }, props: { items: { required: true, type: Object } },
data() { data() {
return { selected_item: {}, show_details_modal: false } return { selectedItem: {}, showDetailsModal: false }
}, },
methods: { methods: {
open(item) { open(item) {
this.selected_item = item this.selectedItem = item
this.$router.push({ this.$router.push({
name: 'music-composer-albums', name: 'music-composer-albums',
params: { name: item.name } params: { name: item.name }
@ -55,8 +55,8 @@ export default {
}, },
openDialog(item) { openDialog(item) {
this.selected_item = item this.selectedItem = item
this.show_details_modal = true this.showDetailsModal = true
} }
} }
} }

View File

@ -38,9 +38,9 @@
</template> </template>
<teleport to="#app"> <teleport to="#app">
<modal-dialog-directory <modal-dialog-directory
:item="selected_item" :item="selectedItem"
:show="show_details_modal" :show="showDetailsModal"
@close="show_details_modal = false" @close="showDetailsModal = false"
/> />
</teleport> </teleport>
</template> </template>
@ -54,7 +54,7 @@ export default {
props: { items: { required: true, type: Array } }, props: { items: { required: true, type: Array } },
data() { data() {
return { selected_item: '', show_details_modal: false } return { selectedItem: '', showDetailsModal: false }
}, },
computed: { computed: {
@ -81,8 +81,8 @@ export default {
this.$router.push(route) this.$router.push(route)
}, },
openDialog(item) { openDialog(item) {
this.selected_item = item.path this.selectedItem = item.path
this.show_details_modal = true this.showDetailsModal = true
}, },
openParent() { openParent() {
this.open(this.directories.slice(-1).pop()) this.open(this.directories.slice(-1).pop())

View File

@ -26,10 +26,10 @@
</template> </template>
<teleport to="#app"> <teleport to="#app">
<modal-dialog-genre <modal-dialog-genre
:item="selected_item" :item="selectedItem"
:media_kind="media_kind" :media_kind="media_kind"
:show="show_details_modal" :show="showDetailsModal"
@close="show_details_modal = false" @close="showDetailsModal = false"
/> />
</teleport> </teleport>
</template> </template>
@ -45,7 +45,7 @@ export default {
media_kind: { required: true, type: String } media_kind: { required: true, type: String }
}, },
data() { data() {
return { selected_item: {}, show_details_modal: false } return { selectedItem: {}, showDetailsModal: false }
}, },
methods: { methods: {
open(item) { open(item) {
@ -56,8 +56,8 @@ export default {
}) })
}, },
openDialog(item) { openDialog(item) {
this.selected_item = item this.selectedItem = item
this.show_details_modal = true this.showDetailsModal = true
} }
} }
} }

View File

@ -1,10 +1,10 @@
<template> <template>
<div <div
v-if="isNext || !show_only_next_items" v-if="isNext || !hideReadItems"
class="media is-align-items-center is-clickable mb-0" class="media is-align-items-center is-clickable mb-0"
@click="play" @click="play"
> >
<div v-if="edit_mode" class="media-left"> <div v-if="editing" class="media-left">
<mdicon <mdicon
class="icon has-text-grey is-movable" class="icon has-text-grey is-movable"
name="drag-horizontal" name="drag-horizontal"
@ -53,10 +53,10 @@ export default {
name: 'ListItemQueueItem', name: 'ListItemQueueItem',
props: { props: {
current_position: { required: true, type: Number }, current_position: { required: true, type: Number },
edit_mode: Boolean, editing: Boolean,
item: { required: true, type: Object }, item: { required: true, type: Object },
position: { required: true, type: Number }, position: { required: true, type: Number },
show_only_next_items: Boolean hideReadItems: Boolean
}, },
setup() { setup() {
return { playerStore: usePlayerStore() } return { playerStore: usePlayerStore() }

View File

@ -18,8 +18,8 @@
<teleport to="#app"> <teleport to="#app">
<modal-dialog-playlist <modal-dialog-playlist
:item="selectedItem" :item="selectedItem"
:show="show_details_modal" :show="showDetailsModal"
@close="show_details_modal = false" @close="showDetailsModal = false"
/> />
</teleport> </teleport>
</template> </template>
@ -33,7 +33,7 @@ export default {
props: { items: { required: true, type: Object } }, props: { items: { required: true, type: Object } },
data() { data() {
return { selectedItem: {}, show_details_modal: false } return { selectedItem: {}, showDetailsModal: false }
}, },
methods: { methods: {
@ -54,7 +54,7 @@ export default {
}, },
openDialog(item) { openDialog(item) {
this.selectedItem = item this.selectedItem = item
this.show_details_modal = true this.showDetailsModal = true
} }
} }
} }

View File

@ -20,9 +20,9 @@
</template> </template>
<teleport to="#app"> <teleport to="#app">
<modal-dialog-playlist-spotify <modal-dialog-playlist-spotify
:item="selected_item" :item="selectedItem"
:show="show_details_modal" :show="showDetailsModal"
@close="show_details_modal = false" @close="showDetailsModal = false"
/> />
</teleport> </teleport>
</template> </template>
@ -38,7 +38,7 @@ export default {
props: { items: { required: true, type: Object } }, props: { items: { required: true, type: Object } },
data() { data() {
return { selected_item: {}, show_details_modal: false } return { selectedItem: {}, showDetailsModal: false }
}, },
methods: { methods: {
@ -46,8 +46,8 @@ export default {
this.$router.push({ name: 'playlist-spotify', params: { id: item.id } }) this.$router.push({ name: 'playlist-spotify', params: { id: item.id } })
}, },
openDialog(item) { openDialog(item) {
this.selected_item = item this.selectedItem = item
this.show_details_modal = true this.showDetailsModal = true
} }
} }
} }

View File

@ -10,11 +10,11 @@
<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"
:class="{ 'with-progress': show_progress }" :class="{ 'with-progress': showProgress }"
@click="play(item.item)" @click="play(item.item)"
> >
<mdicon <mdicon
v-if="show_icon" v-if="showIcon"
class="media-left icon" class="media-left icon"
name="file-music-outline" name="file-music-outline"
/> />
@ -33,7 +33,7 @@
/> />
<div class="is-size-7 has-text-grey" v-text="item.item.album" /> <div class="is-size-7 has-text-grey" v-text="item.item.album" />
<progress <progress
v-if="show_progress && item.item.seek_ms > 0" v-if="showProgress && item.item.seek_ms > 0"
class="progress is-dark" class="progress is-dark"
:max="item.item.length_ms" :max="item.item.length_ms"
:value="item.item.seek_ms" :value="item.item.seek_ms"
@ -48,9 +48,9 @@
</template> </template>
<teleport to="#app"> <teleport to="#app">
<modal-dialog-track <modal-dialog-track
:item="selected_item" :item="selectedItem"
:show="show_details_modal" :show="showDetailsModal"
@close="show_details_modal = false" @close="showDetailsModal = false"
@play-count-changed="$emit('play-count-changed')" @play-count-changed="$emit('play-count-changed')"
/> />
</teleport> </teleport>
@ -66,20 +66,18 @@ export default {
props: { props: {
expression: { default: '', type: String }, expression: { default: '', type: String },
items: { required: true, type: Object }, items: { required: true, type: Object },
show_icon: Boolean, showIcon: Boolean,
show_progress: Boolean, showProgress: Boolean,
uris: { default: '', type: String } uris: { default: '', type: String }
}, },
emits: ['play-count-changed'], emits: ['play-count-changed'],
data() { data() {
return { selected_item: {}, show_details_modal: false } return { selectedItem: {}, showDetailsModal: false }
}, },
methods: { methods: {
openDialog(item) { openDialog(item) {
this.selected_item = item this.selectedItem = item
this.show_details_modal = true this.showDetailsModal = true
}, },
play(item) { play(item) {
if (this.uris) { if (this.uris) {

View File

@ -44,9 +44,9 @@
</template> </template>
<teleport to="#app"> <teleport to="#app">
<modal-dialog-track-spotify <modal-dialog-track-spotify
:item="selected_item" :item="selectedItem"
:show="show_details_modal" :show="showDetailsModal"
@close="show_details_modal = false" @close="showDetailsModal = false"
/> />
</teleport> </teleport>
</template> </template>
@ -63,12 +63,12 @@ export default {
items: { required: true, type: Object } items: { required: true, type: Object }
}, },
data() { data() {
return { selected_item: {}, show_details_modal: false } return { selectedItem: {}, showDetailsModal: false }
}, },
methods: { methods: {
openDialog(item) { openDialog(item) {
this.selected_item = item this.selectedItem = item
this.show_details_modal = true this.showDetailsModal = true
}, },
play(item) { play(item) {
if (item.is_playable) { if (item.is_playable) {

View File

@ -10,7 +10,7 @@
<template v-for="(verse, index) in lyrics" :key="index"> <template v-for="(verse, index) in lyrics" :key="index">
<div <div
v-if="index === verse_index" v-if="index === verse_index"
:class="{ 'is-highlighted': is_playing }" :class="{ 'is-highlighted': playerStore.isPlaying }"
> >
<span <span
v-for="word in verse.words" v-for="word in verse.words"
@ -53,9 +53,6 @@ export default {
} }
}, },
computed: { computed: {
is_playing() {
return this.playerStore.state === 'play'
},
lyrics() { lyrics() {
const raw = this.lyricsStore.content const raw = this.lyricsStore.content
const parsed = [] const parsed = []

View File

@ -25,11 +25,11 @@ export default {
if (this.media_kind_resolved === 'podcast') { if (this.media_kind_resolved === 'podcast') {
if (this.item.data_kind === 'url') { if (this.item.data_kind === 'url') {
return [ return [
{ handler: this.mark_played, key: 'actions.mark-as-played' }, { handler: this.markAsPlayed, key: 'actions.mark-as-played' },
{ handler: this.remove_podcast, key: 'actions.remove-podcast' } { handler: this.removePodcast, key: 'actions.remove-podcast' }
] ]
} }
return [{ handler: this.mark_played, key: 'actions.mark-as-played' }] return [{ handler: this.markAsPlayed, key: 'actions.mark-as-played' }]
} }
return [] return []
}, },
@ -71,7 +71,7 @@ export default {
} }
}, },
methods: { methods: {
mark_played() { markAsPlayed() {
webapi webapi
.library_album_track_update(this.item.id, { play_count: 'played' }) .library_album_track_update(this.item.id, { play_count: 'played' })
.then(() => { .then(() => {
@ -109,7 +109,7 @@ export default {
}) })
} }
}, },
remove_podcast() { removePodcast() {
this.$emit('remove-podcast') this.$emit('remove-podcast')
} }
} }

View File

@ -7,7 +7,10 @@
> >
<template #content> <template #content>
<div v-if="!libraryStore.updating"> <div v-if="!libraryStore.updating">
<div v-if="spotify_enabled || rss.tracks > 0" class="field"> <div
v-if="servicesStore.isSpotifyEnabled || rss.tracks > 0"
class="field"
>
<label class="label" v-text="$t('dialog.update.info')" /> <label class="label" v-text="$t('dialog.update.info')" />
<div class="control"> <div class="control">
<div class="select is-small"> <div class="select is-small">
@ -15,7 +18,7 @@
<option value="" v-text="$t('dialog.update.all')" /> <option value="" v-text="$t('dialog.update.all')" />
<option value="files" v-text="$t('dialog.update.local')" /> <option value="files" v-text="$t('dialog.update.local')" />
<option <option
v-if="spotify_enabled" v-if="servicesStore.isSpotifyEnabled"
value="spotify" value="spotify"
v-text="$t('dialog.update.spotify')" v-text="$t('dialog.update.spotify')"
/> />
@ -80,9 +83,6 @@ export default {
}, },
rss() { rss() {
return this.libraryStore.rss return this.libraryStore.rss
},
spotify_enabled() {
return this.servicesStore.spotify.webapi_token_valid
} }
}, },
methods: { methods: {

View File

@ -1,13 +1,10 @@
<template> <template>
<nav <nav class="navbar is-fixed-bottom" :class="{ 'is-dark': !isNowPlayingPage }">
class="navbar is-fixed-bottom"
:class="{ 'is-dark': !is_now_playing_page }"
>
<div class="navbar-brand is-flex-grow-1"> <div class="navbar-brand is-flex-grow-1">
<control-link class="navbar-item" :to="{ name: 'queue' }"> <control-link class="navbar-item" :to="{ name: 'queue' }">
<mdicon class="icon" name="playlist-play" /> <mdicon class="icon" name="playlist-play" />
</control-link> </control-link>
<template v-if="is_now_playing_page"> <template v-if="isNowPlayingPage">
<control-player-previous class="navbar-item ml-auto" /> <control-player-previous class="navbar-item ml-auto" />
<control-player-back class="navbar-item" :offset="10000" /> <control-player-back class="navbar-item" :offset="10000" />
<control-player-play class="navbar-item" show_disabled_message /> <control-player-play class="navbar-item" show_disabled_message />
@ -21,26 +18,30 @@
class="navbar-item is-justify-content-flex-start is-expanded is-clipped is-size-7" class="navbar-item is-justify-content-flex-start is-expanded is-clipped is-size-7"
> >
<div class="is-text-clipped"> <div class="is-text-clipped">
<strong v-text="current.title" /> <strong v-text="queueStore.current.title" />
<br /> <br />
<span v-text="current.artist" /> <span v-text="queueStore.current.artist" />
<span <span
v-if="current.album" v-if="queueStore.current.album"
v-text="$t('navigation.now-playing', { album: current.album })" v-text="
$t('navigation.now-playing', {
album: queueStore.current.album
})
"
/> />
</div> </div>
</control-link> </control-link>
<control-player-play class="navbar-item" show_disabled_message /> <control-player-play class="navbar-item" show_disabled_message />
</template> </template>
<a class="navbar-item" @click="toggle"> <a class="navbar-item" @click="uiStore.togglePlayerMenu">
<mdicon <mdicon
class="icon" class="icon"
:name="uiStore.show_player_menu ? 'chevron-down' : 'chevron-up'" :name="uiStore.showPlayerMenu ? 'chevron-down' : 'chevron-up'"
/> />
</a> </a>
<div <div
class="dropdown is-up is-right" class="dropdown is-up is-right"
:class="{ 'is-active': uiStore.show_player_menu }" :class="{ 'is-active': uiStore.showPlayerMenu }"
> >
<div class="dropdown-menu is-mobile"> <div class="dropdown-menu is-mobile">
<div class="dropdown-content"> <div class="dropdown-content">
@ -105,7 +106,6 @@ export default {
ControlPlayerShuffle, ControlPlayerShuffle,
ControlStreamVolume ControlStreamVolume
}, },
setup() { setup() {
return { return {
notificationsStore: useNotificationsStore(), notificationsStore: useNotificationsStore(),
@ -114,20 +114,10 @@ export default {
uiStore: useUIStore() uiStore: useUIStore()
} }
}, },
computed: { computed: {
current() { isNowPlayingPage() {
return this.queueStore.current
},
is_now_playing_page() {
return this.$route.name === 'now-playing' return this.$route.name === 'now-playing'
} }
},
methods: {
toggle() {
this.uiStore.show_player_menu = !this.uiStore.show_player_menu
this.uiStore.show_burger_menu = false
}
} }
} }
</script> </script>

View File

@ -9,18 +9,15 @@
> >
<mdicon class="icon" :name="menu.icon" size="16" /> <mdicon class="icon" :name="menu.icon" size="16" />
</control-link> </control-link>
<a <a class="navbar-item ml-auto" @click="uiStore.toggleBurgerMenu">
class="navbar-item ml-auto"
@click="uiStore.show_burger_menu = !uiStore.show_burger_menu"
>
<mdicon <mdicon
class="icon" class="icon"
:name="uiStore.show_burger_menu ? 'close' : 'menu'" :name="uiStore.showBurgerMenu ? 'close' : 'menu'"
/> />
</a> </a>
<div <div
class="dropdown is-right" class="dropdown is-right"
:class="{ 'is-active': uiStore.show_burger_menu }" :class="{ 'is-active': uiStore.showBurgerMenu }"
> >
<div class="dropdown-menu is-mobile"> <div class="dropdown-menu is-mobile">
<div class="dropdown-content"> <div class="dropdown-content">
@ -161,7 +158,7 @@ export default {
] ]
}, },
zindex() { zindex() {
if (this.uiStore.show_player_menu) { if (this.uiStore.showPlayerMenu) {
return 'z-index: 21' return 'z-index: 21'
} }
return '' return ''
@ -169,8 +166,8 @@ export default {
}, },
methods: { methods: {
openUpdateDialog() { openUpdateDialog() {
this.uiStore.show_update_dialog = true this.uiStore.showUpdateDialog = true
this.uiStore.show_burger_menu = false this.uiStore.hideMenus()
} }
} }
} }

View File

@ -1,5 +1,5 @@
<template> <template>
<section v-if="spotify_enabled"> <section v-if="servicesStore.isSpotifyEnabled">
<div class="container"> <div class="container">
<div class="columns is-centered"> <div class="columns is-centered">
<div class="column is-four-fifths"> <div class="column is-four-fifths">
@ -41,11 +41,6 @@ export default {
emits: ['search-library', 'search-spotify'], emits: ['search-library', 'search-spotify'],
setup() { setup() {
return { servicesStore: useServicesStore() } return { servicesStore: useServicesStore() }
},
computed: {
spotify_enabled() {
return this.servicesStore.spotify.webapi_token_valid
}
} }
} }
</script> </script>

View File

@ -7,7 +7,7 @@
<template #heading-right> <template #heading-right>
<control-button <control-button
:button="{ :button="{
handler: showUpdateDialog, handler: openUpdateDialog,
icon: 'refresh', icon: 'refresh',
key: 'page.about.update' key: 'page.about.update'
}" }"
@ -139,8 +139,8 @@ export default {
} }
}, },
methods: { methods: {
showUpdateDialog() { openUpdateDialog() {
this.uiStore.show_update_dialog = true this.uiStore.showUpdateDialog = true
} }
} }
} }

View File

@ -32,8 +32,8 @@
<list-tracks :items="tracks" :uris="album.uri" /> <list-tracks :items="tracks" :uris="album.uri" />
<modal-dialog-album <modal-dialog-album
:item="album" :item="album"
:show="show_details_modal" :show="showDetailsModal"
@close="show_details_modal = false" @close="showDetailsModal = false"
/> />
</template> </template>
</content-with-hero> </content-with-hero>
@ -86,13 +86,13 @@ export default {
data() { data() {
return { return {
album: {}, album: {},
show_details_modal: false, showDetailsModal: false,
tracks: new GroupedList() tracks: new GroupedList()
} }
}, },
methods: { methods: {
openArtist() { openArtist() {
this.show_details_modal = false this.showDetailsModal = false
this.$router.push({ this.$router.push({
name: 'music-artist', name: 'music-artist',
params: { id: this.album.artist_id } params: { id: this.album.artist_id }
@ -102,7 +102,7 @@ export default {
webapi.player_play_uri(this.album.uri, true) webapi.player_play_uri(this.album.uri, true)
}, },
showDetails() { showDetails() {
this.show_details_modal = true this.showDetailsModal = true
} }
} }
} }

View File

@ -32,8 +32,8 @@
<list-tracks-spotify :items="tracks" :context_uri="album.uri" /> <list-tracks-spotify :items="tracks" :context_uri="album.uri" />
<modal-dialog-album-spotify <modal-dialog-album-spotify
:item="album" :item="album"
:show="show_details_modal" :show="showDetailsModal"
@close="show_details_modal = false" @close="showDetailsModal = false"
/> />
</template> </template>
</content-with-hero> </content-with-hero>
@ -83,7 +83,7 @@ export default {
data() { data() {
return { return {
album: { artists: [{}], tracks: {} }, album: { artists: [{}], tracks: {} },
show_details_modal: false showDetailsModal: false
} }
}, },
computed: { computed: {
@ -103,11 +103,11 @@ export default {
}) })
}, },
play() { play() {
this.show_details_modal = false this.showDetailsModal = false
webapi.player_play_uri(this.album.uri, true) webapi.player_play_uri(this.album.uri, true)
}, },
showDetails() { showDetails() {
this.show_details_modal = true this.showDetailsModal = true
} }
} }
} }

View File

@ -10,7 +10,7 @@
class="is-size-7 is-uppercase" class="is-size-7 is-uppercase"
v-text="$t('options.filter.title')" v-text="$t('options.filter.title')"
/> />
<control-switch v-model="uiStore.hide_singles"> <control-switch v-model="uiStore.hideSingles">
<template #label> <template #label>
<span v-text="$t('options.filter.hide-singles')" /> <span v-text="$t('options.filter.hide-singles')" />
</template> </template>
@ -19,8 +19,8 @@
</template> </template>
</control-switch> </control-switch>
<control-switch <control-switch
v-if="spotify_enabled" v-if="servicesStore.isSpotifyEnabled"
v-model="uiStore.hide_spotify" v-model="uiStore.hideSpotify"
> >
<template #label> <template #label>
<span v-text="$t('options.filter.hide-spotify')" /> <span v-text="$t('options.filter.hide-spotify')" />
@ -70,7 +70,7 @@ const dataObject = {
return webapi.library_albums('music') return webapi.library_albums('music')
}, },
set(vm, response) { set(vm, response) {
vm.albums_list = new GroupedList(response.data) vm.albumList = new GroupedList(response.data)
} }
} }
@ -95,7 +95,7 @@ export default {
}, },
data() { data() {
return { return {
albums_list: new GroupedList() albumList: new GroupedList()
} }
}, },
computed: { computed: {
@ -104,10 +104,10 @@ export default {
(grouping) => grouping.id === this.uiStore.albums_sort (grouping) => grouping.id === this.uiStore.albums_sort
) )
options.filters = [ options.filters = [
(album) => !this.uiStore.hide_singles || album.track_count > 2, (album) => !this.uiStore.hideSingles || album.track_count > 2,
(album) => !this.uiStore.hide_spotify || album.data_kind !== 'spotify' (album) => !this.uiStore.hideSpotify || album.data_kind !== 'spotify'
] ]
return this.albums_list.group(options) return this.albumList.group(options)
}, },
groupings() { groupings() {
return [ return [
@ -161,9 +161,6 @@ export default {
subtitle: [{ count: this.albums.count, key: 'count.albums' }], subtitle: [{ count: this.albums.count, key: 'count.albums' }],
title: this.$t('page.albums.title') title: this.$t('page.albums.title')
} }
},
spotify_enabled() {
return this.servicesStore.spotify.webapi_token_valid
} }
} }
} }

View File

@ -9,8 +9,8 @@
v-text="$t('page.artist.filter.title')" v-text="$t('page.artist.filter.title')"
/> />
<control-switch <control-switch
v-if="spotify_enabled" v-if="servicesStore.isSpotifyEnabled"
v-model="uiStore.hide_spotify" v-model="uiStore.hideSpotify"
> >
<template #label> <template #label>
<span v-text="$t('page.artist.filter.hide-spotify')" /> <span v-text="$t('page.artist.filter.hide-spotify')" />
@ -47,8 +47,8 @@
<list-albums :items="albums" /> <list-albums :items="albums" />
<modal-dialog-artist <modal-dialog-artist
:item="artist" :item="artist"
:show="show_details_modal" :show="showDetailsModal"
@close="show_details_modal = false" @close="showDetailsModal = false"
/> />
</template> </template>
</content-with-heading> </content-with-heading>
@ -77,7 +77,7 @@ const dataObject = {
}, },
set(vm, response) { set(vm, response) {
vm.artist = response[0].data vm.artist = response[0].data
vm.albums_list = new GroupedList(response[1].data) vm.albumList = new GroupedList(response[1].data)
} }
} }
@ -102,9 +102,9 @@ export default {
}, },
data() { data() {
return { return {
albums_list: new GroupedList(), albumList: new GroupedList(),
artist: {}, artist: {},
show_details_modal: false showDetailsModal: false
} }
}, },
computed: { computed: {
@ -113,9 +113,9 @@ export default {
(grouping) => grouping.id === this.uiStore.artist_albums_sort (grouping) => grouping.id === this.uiStore.artist_albums_sort
) )
options.filters = [ options.filters = [
(album) => !this.uiStore.hide_spotify || album.data_kind !== 'spotify' (album) => !this.uiStore.hideSpotify || album.data_kind !== 'spotify'
] ]
return this.albums_list.group(options) return this.albumList.group(options)
}, },
groupings() { groupings() {
return [ return [
@ -136,7 +136,7 @@ export default {
subtitle: [ subtitle: [
{ count: this.albums.count, key: 'count.albums' }, { count: this.albums.count, key: 'count.albums' },
{ {
count: this.track_count, count: this.trackCount,
handler: this.openTracks, handler: this.openTracks,
key: 'count.tracks' key: 'count.tracks'
} }
@ -144,10 +144,7 @@ export default {
title: this.artist.name title: this.artist.name
} }
}, },
spotify_enabled() { trackCount() {
return this.servicesStore.spotify.webapi_token_valid
},
track_count() {
// The count of tracks is incorrect when albums have Spotify tracks. // The count of tracks is incorrect when albums have Spotify tracks.
return [...this.albums].reduce( return [...this.albums].reduce(
(total, album) => total + (album.isItem ? album.item.track_count : 0), (total, album) => total + (album.isItem ? album.item.track_count : 0),
@ -169,7 +166,7 @@ export default {
) )
}, },
showDetails() { showDetails() {
this.show_details_modal = true this.showDetailsModal = true
} }
} }
} }

View File

@ -14,7 +14,7 @@
</template> </template>
<template #content> <template #content>
<list-albums-spotify :items="albums" /> <list-albums-spotify :items="albums" />
<vue-eternal-loading v-if="offset < total" :load="load_next"> <vue-eternal-loading v-if="offset < total" :load="loadNext">
<template #loading> <template #loading>
<div class="columns is-centered"> <div class="columns is-centered">
<div class="column has-text-centered"> <div class="column has-text-centered">
@ -31,8 +31,8 @@
</vue-eternal-loading> </vue-eternal-loading>
<modal-dialog-artist-spotify <modal-dialog-artist-spotify
:item="artist" :item="artist"
:show="show_details_modal" :show="showDetailsModal"
@close="show_details_modal = false" @close="showDetailsModal = false"
/> />
</template> </template>
</content-with-heading> </content-with-heading>
@ -71,7 +71,7 @@ const dataObject = {
vm.albums = [] vm.albums = []
vm.total = 0 vm.total = 0
vm.offset = 0 vm.offset = 0
vm.append_albums(response.shift()) vm.appendAlbums(response.shift())
} }
} }
@ -98,7 +98,7 @@ export default {
albums: [], albums: [],
artist: {}, artist: {},
offset: 0, offset: 0,
show_details_modal: false, showDetailsModal: false,
total: 0 total: 0
} }
}, },
@ -111,12 +111,12 @@ export default {
} }
}, },
methods: { methods: {
append_albums(data) { appendAlbums(data) {
this.albums = this.albums.concat(data.items) this.albums = this.albums.concat(data.items)
this.total = data.total this.total = data.total
this.offset += data.limit this.offset += data.limit
}, },
load_next({ loaded }) { loadNext({ loaded }) {
const spotifyApi = new SpotifyWebApi() const spotifyApi = new SpotifyWebApi()
spotifyApi.setAccessToken(this.servicesStore.spotify.webapi_token) spotifyApi.setAccessToken(this.servicesStore.spotify.webapi_token)
spotifyApi spotifyApi
@ -126,16 +126,16 @@ export default {
offset: this.offset offset: this.offset
}) })
.then((data) => { .then((data) => {
this.append_albums(data) this.appendAlbums(data)
loaded(data.items.length, PAGE_SIZE) loaded(data.items.length, PAGE_SIZE)
}) })
}, },
play() { play() {
this.show_album_details_modal = false this.showDetailsModal = false
webapi.player_play_uri(this.artist.uri, true) webapi.player_play_uri(this.artist.uri, true)
}, },
showDetails() { showDetails() {
this.show_details_modal = true this.showDetailsModal = true
} }
} }
} }

View File

@ -10,8 +10,8 @@
v-text="$t('options.filter.title')" v-text="$t('options.filter.title')"
/> />
<control-switch <control-switch
v-if="spotify_enabled" v-if="servicesStore.isSpotifyEnabled"
v-model="uiStore.hide_spotify" v-model="uiStore.hideSpotify"
> >
<template #label> <template #label>
<span v-text="$t('options.filter.hide-spotify')" /> <span v-text="$t('options.filter.hide-spotify')" />
@ -48,8 +48,8 @@
<list-tracks :items="tracks" :uris="track_uris" /> <list-tracks :items="tracks" :uris="track_uris" />
<modal-dialog-artist <modal-dialog-artist
:item="artist" :item="artist"
:show="show_details_modal" :show="showDetailsModal"
@close="show_details_modal = false" @close="showDetailsModal = false"
/> />
</template> </template>
</content-with-heading> </content-with-heading>
@ -79,7 +79,7 @@ const dataObject = {
}, },
set(vm, response) { set(vm, response) {
vm.artist = response[0].data vm.artist = response[0].data
vm.tracks_list = new GroupedList(response[1].data.tracks) vm.trackList = new GroupedList(response[1].data.tracks)
} }
} }
@ -106,8 +106,8 @@ export default {
data() { data() {
return { return {
artist: {}, artist: {},
show_details_modal: false, showDetailsModal: false,
tracks_list: new GroupedList() trackList: new GroupedList()
} }
}, },
computed: { computed: {
@ -148,25 +148,22 @@ export default {
title: this.artist.name title: this.artist.name
} }
}, },
spotify_enabled() {
return this.servicesStore.spotify.webapi_token_valid
},
track_uris() { track_uris() {
return this.tracks_list.items.map((item) => item.uri).join() return this.trackList.items.map((item) => item.uri).join()
}, },
tracks() { tracks() {
const { options } = this.groupings.find( const { options } = this.groupings.find(
(grouping) => grouping.id === this.uiStore.artist_tracks_sort (grouping) => grouping.id === this.uiStore.artist_tracks_sort
) )
options.filters = [ options.filters = [
(track) => !this.uiStore.hide_spotify || track.data_kind !== 'spotify' (track) => !this.uiStore.hideSpotify || track.data_kind !== 'spotify'
] ]
return this.tracks_list.group(options) return this.trackList.group(options)
} }
}, },
methods: { methods: {
openArtist() { openArtist() {
this.show_details_modal = false this.showDetailsModal = false
this.$router.push({ this.$router.push({
name: 'music-artist', name: 'music-artist',
params: { id: this.artist.id } params: { id: this.artist.id }
@ -174,12 +171,12 @@ export default {
}, },
play() { play() {
webapi.player_play_uri( webapi.player_play_uri(
this.tracks_list.items.map((item) => item.uri).join(), this.trackList.items.map((item) => item.uri).join(),
true true
) )
}, },
showDetails() { showDetails() {
this.show_details_modal = true this.showDetailsModal = true
} }
} }
} }

View File

@ -10,7 +10,7 @@
class="is-size-7 is-uppercase" class="is-size-7 is-uppercase"
v-text="$t('options.filter.title')" v-text="$t('options.filter.title')"
/> />
<control-switch v-model="uiStore.hide_singles"> <control-switch v-model="uiStore.hideSingles">
<template #label> <template #label>
<span v-text="$t('options.filter.hide-singles')" /> <span v-text="$t('options.filter.hide-singles')" />
</template> </template>
@ -18,8 +18,8 @@
<span v-text="$t('options.filter.hide-singles-help')" /> <span v-text="$t('options.filter.hide-singles-help')" />
</template> </template>
</control-switch> </control-switch>
<div v-if="spotify_enabled" class="field"> <div v-if="servicesStore.isSpotifyEnabled" class="field">
<control-switch v-model="uiStore.hide_spotify"> <control-switch v-model="uiStore.hideSpotify">
<template #label> <template #label>
<span v-text="$t('options.filter.hide-spotify')" /> <span v-text="$t('options.filter.hide-spotify')" />
</template> </template>
@ -69,7 +69,7 @@ const dataObject = {
return webapi.library_artists('music') return webapi.library_artists('music')
}, },
set(vm, response) { set(vm, response) {
vm.artists_list = new GroupedList(response.data) vm.artistList = new GroupedList(response.data)
} }
} }
@ -94,7 +94,7 @@ export default {
}, },
data() { data() {
return { return {
artists_list: new GroupedList() artistList: new GroupedList()
} }
}, },
computed: { computed: {
@ -104,11 +104,11 @@ export default {
) )
options.filters = [ options.filters = [
(artist) => (artist) =>
!this.uiStore.hide_singles || !this.uiStore.hideSingles ||
artist.track_count > artist.album_count * 2, artist.track_count > artist.album_count * 2,
(artist) => !this.uiStore.hide_spotify || artist.data_kind !== 'spotify' (artist) => !this.uiStore.hideSpotify || artist.data_kind !== 'spotify'
] ]
return this.artists_list.group(options) return this.artistList.group(options)
}, },
groupings() { groupings() {
return [ return [
@ -132,9 +132,6 @@ export default {
subtitle: [{ count: this.artists.count, key: 'count.artists' }], subtitle: [{ count: this.artists.count, key: 'count.artists' }],
title: this.$t('page.artists.title') title: this.$t('page.artists.title')
} }
},
spotify_enabled() {
return this.servicesStore.spotify.webapi_token_valid
} }
} }
} }

View File

@ -15,7 +15,7 @@
:button="{ :button="{
handler: play, handler: play,
icon: 'play', icon: 'play',
key: 'page.audiobooks.album.play' key: 'actions.play'
}" }"
/> />
<control-button <control-button
@ -33,12 +33,12 @@
/> />
</template> </template>
<template #content> <template #content>
<list-tracks :items="tracks" :show_progress="true" :uris="album.uri" /> <list-tracks :items="tracks" :show-progress="true" :uris="album.uri" />
<modal-dialog-album <modal-dialog-album
:item="album" :item="album"
:show="show_details_modal" :show="showDetailsModal"
:media_kind="'audiobook'" :media_kind="'audiobook'"
@close="show_details_modal = false" @close="showDetailsModal = false"
/> />
</template> </template>
</content-with-hero> </content-with-hero>
@ -84,13 +84,13 @@ export default {
data() { data() {
return { return {
album: {}, album: {},
show_details_modal: false, showDetailsModal: false,
tracks: new GroupedList() tracks: new GroupedList()
} }
}, },
methods: { methods: {
openArtist() { openArtist() {
this.show_details_modal = false this.showDetailsModal = false
this.$router.push({ this.$router.push({
name: 'audiobooks-artist', name: 'audiobooks-artist',
params: { id: this.album.artist_id } params: { id: this.album.artist_id }
@ -100,7 +100,7 @@ export default {
webapi.player_play_uri(this.album.uri, false) webapi.player_play_uri(this.album.uri, false)
}, },
showDetails() { showDetails() {
this.show_details_modal = true this.showDetailsModal = true
} }
} }
} }

View File

@ -20,8 +20,8 @@
<list-albums :items="albums" /> <list-albums :items="albums" />
<modal-dialog-artist <modal-dialog-artist
:item="artist" :item="artist"
:show="show_details_modal" :show="showDetailsModal"
@close="show_details_modal = false" @close="showDetailsModal = false"
/> />
</template> </template>
</content-with-heading> </content-with-heading>
@ -68,7 +68,7 @@ export default {
return { return {
albums: new GroupedList(), albums: new GroupedList(),
artist: {}, artist: {},
show_details_modal: false showDetailsModal: false
} }
}, },
computed: { computed: {
@ -92,7 +92,7 @@ export default {
) )
}, },
showDetails() { showDetails() {
this.show_details_modal = true this.showDetailsModal = true
} }
} }
} }

View File

@ -16,8 +16,8 @@
<list-albums :items="albums" /> <list-albums :items="albums" />
<modal-dialog-composer <modal-dialog-composer
:item="composer" :item="composer"
:show="show_details_modal" :show="showDetailsModal"
@close="show_details_modal = false" @close="showDetailsModal = false"
/> />
</template> </template>
</content-with-heading> </content-with-heading>
@ -64,7 +64,7 @@ export default {
return { return {
albums: new GroupedList(), albums: new GroupedList(),
composer: {}, composer: {},
show_details_modal: false showDetailsModal: false
} }
}, },
computed: { computed: {
@ -99,7 +99,7 @@ export default {
webapi.player_play_expression(this.expression, true) webapi.player_play_expression(this.expression, true)
}, },
showDetails() { showDetails() {
this.show_details_modal = true this.showDetailsModal = true
} }
} }
} }

View File

@ -31,8 +31,8 @@
<list-tracks :items="tracks" :expression="expression" /> <list-tracks :items="tracks" :expression="expression" />
<modal-dialog-composer <modal-dialog-composer
:item="composer" :item="composer"
:show="show_details_modal" :show="showDetailsModal"
@close="show_details_modal = false" @close="showDetailsModal = false"
/> />
</template> </template>
</content-with-heading> </content-with-heading>
@ -60,7 +60,7 @@ const dataObject = {
}, },
set(vm, response) { set(vm, response) {
vm.composer = response[0].data vm.composer = response[0].data
vm.tracks_list = new GroupedList(response[1].data.tracks) vm.trackList = new GroupedList(response[1].data.tracks)
} }
} }
@ -86,8 +86,8 @@ export default {
data() { data() {
return { return {
composer: {}, composer: {},
show_details_modal: false, showDetailsModal: false,
tracks_list: new GroupedList() trackList: new GroupedList()
} }
}, },
computed: { computed: {
@ -145,7 +145,7 @@ export default {
webapi.player_play_expression(this.expression, true) webapi.player_play_expression(this.expression, true)
}, },
showDetails() { showDetails() {
this.show_details_modal = true this.showDetailsModal = true
} }
} }
} }

View File

@ -18,12 +18,12 @@
<list-tracks <list-tracks
:expression="expression" :expression="expression"
:items="tracks" :items="tracks"
:show_icon="true" :show-icon="true"
/> />
<modal-dialog-directory <modal-dialog-directory
:item="current" :item="current"
:show="show_details_modal" :show="showDetailsModal"
@close="show_details_modal = false" @close="showDetailsModal = false"
/> />
</template> </template>
</content-with-heading> </content-with-heading>
@ -101,7 +101,7 @@ export default {
return { return {
directories: [], directories: [],
playlists: new GroupedList(), playlists: new GroupedList(),
show_details_modal: false, showDetailsModal: false,
tracks: new GroupedList() tracks: new GroupedList()
} }
}, },
@ -124,7 +124,7 @@ export default {
webapi.player_play_expression(this.expression, false) webapi.player_play_expression(this.expression, false)
}, },
showDetails() { showDetails() {
this.show_details_modal = true this.showDetailsModal = true
}, },
transform(path) { transform(path) {
return { name: path.slice(path.lastIndexOf('/') + 1), path } return { name: path.slice(path.lastIndexOf('/') + 1), path }

View File

@ -20,8 +20,8 @@
<modal-dialog-genre <modal-dialog-genre
:item="genre" :item="genre"
:media_kind="media_kind" :media_kind="media_kind"
:show="show_details_modal" :show="showDetailsModal"
@close="show_details_modal = false" @close="showDetailsModal = false"
/> />
</template> </template>
</content-with-heading> </content-with-heading>
@ -73,7 +73,7 @@ export default {
albums: new GroupedList(), albums: new GroupedList(),
genre: {}, genre: {},
media_kind: this.$route.query.media_kind, media_kind: this.$route.query.media_kind,
show_details_modal: false showDetailsModal: false
} }
}, },
computed: { computed: {
@ -96,7 +96,7 @@ export default {
}, },
methods: { methods: {
openTracks() { openTracks() {
this.show_details_modal = false this.showDetailsModal = false
this.$router.push({ this.$router.push({
name: 'genre-tracks', name: 'genre-tracks',
params: { name: this.genre.name }, params: { name: this.genre.name },
@ -110,7 +110,7 @@ export default {
) )
}, },
showDetails() { showDetails() {
this.show_details_modal = true this.showDetailsModal = true
} }
} }
} }

View File

@ -32,8 +32,8 @@
<modal-dialog-genre <modal-dialog-genre
:item="genre" :item="genre"
:media_kind="media_kind" :media_kind="media_kind"
:show="show_details_modal" :show="showDetailsModal"
@close="show_details_modal = false" @close="showDetailsModal = false"
/> />
</template> </template>
</content-with-heading> </content-with-heading>
@ -61,7 +61,7 @@ const dataObject = {
}, },
set(vm, response) { set(vm, response) {
vm.genre = response[0].data.genres.items.shift() vm.genre = response[0].data.genres.items.shift()
vm.tracks_list = new GroupedList(response[1].data.tracks) vm.trackList = new GroupedList(response[1].data.tracks)
} }
} }
@ -88,8 +88,8 @@ export default {
return { return {
genre: {}, genre: {},
media_kind: this.$route.query.media_kind, media_kind: this.$route.query.media_kind,
show_details_modal: false, showDetailsModal: false,
tracks_list: new GroupedList() trackList: new GroupedList()
} }
}, },
computed: { computed: {
@ -133,12 +133,12 @@ export default {
const { options } = this.groupings.find( const { options } = this.groupings.find(
(grouping) => grouping.id === this.uiStore.genre_tracks_sort (grouping) => grouping.id === this.uiStore.genre_tracks_sort
) )
return this.tracks_list.group(options) return this.trackList.group(options)
} }
}, },
methods: { methods: {
openGenre() { openGenre() {
this.show_details_modal = false this.showDetailsModal = false
this.$router.push({ this.$router.push({
name: 'genre-albums', name: 'genre-albums',
params: { name: this.genre.name }, params: { name: this.genre.name },
@ -149,7 +149,7 @@ export default {
webapi.player_play_expression(this.expression, true) webapi.player_play_expression(this.expression, true)
}, },
showDetails() { showDetails() {
this.show_details_modal = true this.showDetailsModal = true
} }
} }
} }

View File

@ -89,7 +89,6 @@ export default {
data() { data() {
return { return {
albums: [], albums: [],
selected_track: {},
tracks: { items: [] } tracks: { items: [] }
} }
} }

View File

@ -8,10 +8,10 @@
:artist="track.artist" :artist="track.artist"
:album="track.album" :album="track.album"
class="is-clickable is-big" class="is-clickable is-big"
:class="{ 'is-masked': lyricsStore.pane }" :class="{ 'is-masked': lyricsStore.active }"
@click="openDialog(track)" @click="openDialog(track)"
/> />
<lyrics-pane v-if="lyricsStore.pane" /> <lyrics-pane v-if="lyricsStore.active" />
<control-slider <control-slider
v-model:value="track_progress" v-model:value="track_progress"
class="mt-5" class="mt-5"
@ -45,9 +45,9 @@
</div> </div>
</div> </div>
<modal-dialog-queue-item <modal-dialog-queue-item
:show="show_details_modal" :show="showDetailsModal"
:item="selected_item" :item="selectedItem"
@close="show_details_modal = false" @close="showDetailsModal = false"
/> />
</template> </template>
@ -85,8 +85,8 @@ export default {
INTERVAL, INTERVAL,
interval_id: 0, interval_id: 0,
is_dragged: false, is_dragged: false,
selected_item: {}, selectedItem: {},
show_details_modal: false showDetailsModal: false
} }
}, },
computed: { computed: {
@ -165,8 +165,8 @@ export default {
this.is_dragged = false this.is_dragged = false
}, },
openDialog(item) { openDialog(item) {
this.selected_item = item this.selectedItem = item
this.show_details_modal = true this.showDetailsModal = true
}, },
seek() { seek() {
if (!this.is_live) { if (!this.is_live) {

View File

@ -21,9 +21,9 @@
<list-tracks :items="tracks" :uris="uris" /> <list-tracks :items="tracks" :uris="uris" />
<modal-dialog-playlist <modal-dialog-playlist
:item="playlist" :item="playlist"
:show="show_details_modal" :show="showDetailsModal"
:uris="uris" :uris="uris"
@close="show_details_modal = false" @close="showDetailsModal = false"
/> />
</template> </template>
</content-with-heading> </content-with-heading>
@ -69,7 +69,7 @@ export default {
data() { data() {
return { return {
playlist: {}, playlist: {},
show_details_modal: false, showDetailsModal: false,
tracks: new GroupedList() tracks: new GroupedList()
} }
}, },
@ -92,7 +92,7 @@ export default {
webapi.player_play_uri(this.uris, true) webapi.player_play_uri(this.uris, true)
}, },
showDetails() { showDetails() {
this.show_details_modal = true this.showDetailsModal = true
} }
} }
} }

View File

@ -19,7 +19,7 @@
</template> </template>
<template #content> <template #content>
<list-tracks-spotify :items="tracks" :context_uri="playlist.uri" /> <list-tracks-spotify :items="tracks" :context_uri="playlist.uri" />
<vue-eternal-loading v-if="offset < total" :load="load_next"> <vue-eternal-loading v-if="offset < total" :load="load">
<template #loading> <template #loading>
<div class="columns is-centered"> <div class="columns is-centered">
<div class="column has-text-centered"> <div class="column has-text-centered">
@ -33,8 +33,8 @@
</vue-eternal-loading> </vue-eternal-loading>
<modal-dialog-playlist-spotify <modal-dialog-playlist-spotify
:item="playlist" :item="playlist"
:show="show_playlist_details_modal" :show="showDetailsModal"
@close="show_playlist_details_modal = false" @close="showDetailsModal = false"
/> />
</template> </template>
</content-with-heading> </content-with-heading>
@ -72,7 +72,7 @@ const dataObject = {
vm.tracks = [] vm.tracks = []
vm.total = 0 vm.total = 0
vm.offset = 0 vm.offset = 0
vm.append_tracks(response.shift()) vm.appendTracks(response.shift())
} }
} }
@ -98,23 +98,26 @@ export default {
return { return {
offset: 0, offset: 0,
playlist: { tracks: {} }, playlist: { tracks: {} },
show_playlist_details_modal: false, showDetailsModal: false,
total: 0, total: 0,
tracks: [] tracks: []
} }
}, },
computed: { computed: {
heading() { heading() {
return { if (this.playlist.name) {
subtitle: [ return {
{ count: this.playlist.tracks.total, key: 'count.playlists' } subtitle: [
], { count: this.playlist.tracks.total, key: 'count.playlists' }
title: this.playlist.name ],
title: this.playlist.name
}
} }
return {}
} }
}, },
methods: { methods: {
append_tracks(data) { appendTracks(data) {
let position = Math.max( let position = Math.max(
-1, -1,
...this.tracks.map((item) => item.position).filter((item) => item) ...this.tracks.map((item) => item.position).filter((item) => item)
@ -132,7 +135,7 @@ export default {
this.total = data.total this.total = data.total
this.offset += data.limit this.offset += data.limit
}, },
load_next({ loaded }) { load({ loaded }) {
const spotifyApi = new SpotifyWebApi() const spotifyApi = new SpotifyWebApi()
spotifyApi.setAccessToken(this.servicesStore.spotify.webapi_token) spotifyApi.setAccessToken(this.servicesStore.spotify.webapi_token)
spotifyApi spotifyApi
@ -142,16 +145,16 @@ export default {
offset: this.offset offset: this.offset
}) })
.then((data) => { .then((data) => {
this.append_tracks(data) this.appendTracks(data)
loaded(data.items.length, PAGE_SIZE) loaded(data.items.length, PAGE_SIZE)
}) })
}, },
play() { play() {
this.show_details_modal = false this.showDetailsModal = false
webapi.player_play_uri(this.playlist.uri, true) webapi.player_play_uri(this.playlist.uri, true)
}, },
showDetails() { showDetails() {
this.show_playlist_details_modal = true this.showDetailsModal = true
} }
} }
} }

View File

@ -31,22 +31,22 @@
<template #content> <template #content>
<list-tracks <list-tracks
:items="tracks" :items="tracks"
:show_progress="true" :show-progress="true"
@play-count-changed="reloadTracks" @play-count-changed="reloadTracks"
/> />
<modal-dialog-album <modal-dialog-album
:item="album" :item="album"
:show="show_details_modal" :show="showDetailsModal"
:media_kind="'podcast'" :media_kind="'podcast'"
@close="show_details_modal = false" @close="showDetailsModal = false"
@play-count-changed="reloadTracks" @play-count-changed="reloadTracks"
@remove-podcast="openRemovePodcastDialog" @remove-podcast="openRemovePodcastDialog"
/> />
<modal-dialog <modal-dialog
:actions="actions" :actions="actions"
:show="show_remove_podcast_modal" :show="showRemovePodcastModal"
:title="$t('page.podcast.remove-podcast')" :title="$t('page.podcast.remove-podcast')"
@cancel="show_remove_podcast_modal = false" @cancel="showRemovePodcastModal = false"
@remove="removePodcast" @remove="removePodcast"
> >
<template #content> <template #content>
@ -107,8 +107,8 @@ export default {
return { return {
album: {}, album: {},
rss_playlist_to_remove: {}, rss_playlist_to_remove: {},
show_details_modal: false, showDetailsModal: false,
show_remove_podcast_modal: false, showRemovePodcastModal: false,
tracks: new GroupedList() tracks: new GroupedList()
} }
}, },
@ -136,8 +136,8 @@ export default {
;[this.rss_playlist_to_remove] = data.items.filter( ;[this.rss_playlist_to_remove] = data.items.filter(
(pl) => pl.type === 'rss' (pl) => pl.type === 'rss'
) )
this.show_remove_podcast_modal = true this.showRemovePodcastModal = true
this.show_details_modal = false this.showDetailsModal = false
}) })
}, },
play() { play() {
@ -149,7 +149,7 @@ export default {
}) })
}, },
removePodcast() { removePodcast() {
this.show_remove_podcast_modal = false this.showRemovePodcastModal = false
webapi webapi
.library_playlist_delete(this.rss_playlist_to_remove.id) .library_playlist_delete(this.rss_playlist_to_remove.id)
.then(() => { .then(() => {
@ -157,7 +157,7 @@ export default {
}) })
}, },
showDetails() { showDetails() {
this.show_details_modal = true this.showDetailsModal = true
} }
} }
} }

View File

@ -16,7 +16,7 @@
<template #content> <template #content>
<list-tracks <list-tracks
:items="tracks" :items="tracks"
:show_progress="true" :show-progress="true"
@play-count-changed="reloadNewEpisodes" @play-count-changed="reloadNewEpisodes"
/> />
</template> </template>
@ -49,8 +49,8 @@
@podcast-deleted="reloadPodcasts()" @podcast-deleted="reloadPodcasts()"
/> />
<modal-dialog-add-rss <modal-dialog-add-rss
:show="show_url_modal" :show="showAddPodcastModal"
@close="show_url_modal = false" @close="showAddPodcastModal = false"
@podcast-added="reloadPodcasts()" @podcast-added="reloadPodcasts()"
/> />
</template> </template>
@ -104,7 +104,7 @@ export default {
data() { data() {
return { return {
albums: [], albums: [],
show_url_modal: false, showAddPodcastModal: false,
tracks: { items: [] } tracks: { items: [] }
} }
}, },
@ -130,7 +130,7 @@ export default {
this.tracks.items = {} this.tracks.items = {}
}, },
openAddPodcastDialog() { openAddPodcastDialog() {
this.show_url_modal = true this.showAddPodcastModal = true
}, },
reloadNewEpisodes() { reloadNewEpisodes() {
webapi.library_podcasts_new_episodes().then(({ data }) => { webapi.library_podcasts_new_episodes().then(({ data }) => {
@ -145,7 +145,7 @@ export default {
}, },
updateRss() { updateRss() {
this.libraryStore.update_dialog_scan_kind = 'rss' this.libraryStore.update_dialog_scan_kind = 'rss'
this.uiStore.show_update_dialog = true this.uiStore.showUpdateDialog = true
} }
} }
} }

View File

@ -7,11 +7,11 @@
<template #heading-right> <template #heading-right>
<control-button <control-button
:button="{ :button="{
handler: toggleHideReadItems, handler: uiStore.toggleHideReadItems,
icon: 'eye-off-outline', icon: 'eye-off-outline',
key: 'actions.hide-previous' key: 'actions.hide-previous'
}" }"
:class="{ 'is-dark': uiStore.show_only_next_items }" :class="{ 'is-dark': uiStore.hideReadItems }"
/> />
<control-button <control-button
:button="{ :button="{
@ -26,8 +26,8 @@
icon: 'pencil', icon: 'pencil',
key: 'actions.edit' key: 'actions.edit'
}" }"
:class="{ 'is-dark': edit_mode }" :class="{ 'is-dark': editing }"
:disabled="queue_items.length === 0" :disabled="queueStore.isEmpty"
/> />
<control-button <control-button
:button="{ :button="{
@ -35,30 +35,30 @@
icon: 'delete-empty', icon: 'delete-empty',
key: 'actions.clear' key: 'actions.clear'
}" }"
:disabled="queue_items.length === 0" :disabled="queueStore.isEmpty"
/> />
<control-button <control-button
v-if="is_queue_save_allowed" v-if="queueStore.isSavingAllowed"
:button="{ :button="{
handler: showSaveDialog, handler: openSaveDialog,
icon: 'download', icon: 'download',
key: 'actions.save' key: 'actions.save'
}" }"
:disabled="queue_items.length === 0" :disabled="queueStore.isEmpty"
/> />
</template> </template>
<template #content> <template #content>
<draggable v-model="queue_items" item-key="id" @end="move_item"> <draggable v-model="items" item-key="id" @end="moveItem">
<template #item="{ element, index }"> <template #item="{ element, index }">
<list-item-queue-item <list-item-queue-item
:item="element" :item="element"
:position="index" :position="index"
:current_position="current_position" :current_position="current_position"
:show_only_next_items="uiStore.show_only_next_items" :hide-read-items="uiStore.hideReadItems"
:edit_mode="edit_mode" :editing="editing"
> >
<template #actions> <template #actions>
<a v-if="!edit_mode" @click.prevent.stop="openDialog(element)"> <a v-if="!editing" @click.prevent.stop="openDialog(element)">
<mdicon <mdicon
class="icon has-text-grey" class="icon has-text-grey"
name="dots-vertical" name="dots-vertical"
@ -66,7 +66,7 @@
/> />
</a> </a>
<a <a
v-if="element.id !== player.item_id && edit_mode" v-if="isRemovable(element)"
@click.prevent.stop="remove(element)" @click.prevent.stop="remove(element)"
> >
<mdicon class="icon has-text-grey" name="delete" size="18" /> <mdicon class="icon has-text-grey" name="delete" size="18" />
@ -76,18 +76,18 @@
</template> </template>
</draggable> </draggable>
<modal-dialog-queue-item <modal-dialog-queue-item
:show="show_details_modal" :show="showDetailsModal"
:item="selected_item" :item="selectedItem"
@close="show_details_modal = false" @close="showDetailsModal = false"
/> />
<modal-dialog-add-stream <modal-dialog-add-stream
:show="show_url_modal" :show="showAddStreamDialog"
@close="show_url_modal = false" @close="showAddStreamDialog = false"
/> />
<modal-dialog-playlist-save <modal-dialog-playlist-save
v-if="is_queue_save_allowed" v-if="queueStore.isSavingAllowed"
:show="show_pls_save_modal" :show="showSaveModal"
@close="show_pls_save_modal = false" @close="showSaveModal = false"
/> />
</template> </template>
</content-with-heading> </content-with-heading>
@ -131,78 +131,65 @@ export default {
}, },
data() { data() {
return { return {
edit_mode: false, editing: false,
selected_item: {}, selectedItem: {},
show_details_modal: false, showDetailsModal: false,
show_pls_save_modal: false, showSaveModal: false,
show_url_modal: false showAddStreamDialog: false
} }
}, },
computed: { computed: {
current_position() { current_position() {
return this.queue.current?.position ?? -1 return this.queueStore.current?.position ?? -1
}, },
heading() { heading() {
return { return {
subtitle: [{ count: this.queue.count, key: 'count.tracks' }], subtitle: [{ count: this.queueStore.count, key: 'count.tracks' }],
title: this.$t('page.queue.title') title: this.$t('page.queue.title')
} }
}, },
is_queue_save_allowed() { items: {
return (
this.configurationStore.allow_modifying_stored_playlists &&
this.configurationStore.default_playlist_directory
)
},
player() {
return this.playerStore
},
queue() {
return this.queueStore
},
queue_items: {
get() { get() {
return this.queue.items return this.queueStore.items
}, },
set() { set(value) {
/* Do nothing? Send move request in @end event */ /* Do nothing? Send move request in @end event */
} }
} }
}, },
methods: { methods: {
move_item(event) { clearQueue() {
webapi.queue_clear()
},
isRemovable(item) {
return item.id !== this.playerStore.item_id && this.editing
},
moveItem(event) {
const oldPosition = const oldPosition =
event.oldIndex + event.oldIndex + (this.uiStore.hideReadItems && this.current_position)
(this.uiStore.show_only_next_items && this.current_position) const item = this.items[oldPosition]
const item = this.queue_items[oldPosition]
const newPosition = item.position + (event.newIndex - event.oldIndex) const newPosition = item.position + (event.newIndex - event.oldIndex)
if (newPosition !== oldPosition) { if (newPosition !== oldPosition) {
webapi.queue_move(item.id, newPosition) webapi.queue_move(item.id, newPosition)
} }
}, },
openAddStreamDialog() { openAddStreamDialog() {
this.show_url_modal = true this.showAddStreamDialog = true
}, },
openDialog(item) { openDialog(item) {
this.selected_item = item this.selectedItem = item
this.show_details_modal = true this.showDetailsModal = true
}, },
clearQueue() { openSaveDialog() {
webapi.queue_clear() if (!this.queueStore.isEmpty) {
this.showSaveModal = true
}
}, },
remove(item) { remove(item) {
webapi.queue_remove(item.id) webapi.queue_remove(item.id)
}, },
showSaveDialog() {
if (this.queue_items.length > 0) {
this.show_pls_save_modal = true
}
},
toggleEdit() { toggleEdit() {
this.edit_mode = !this.edit_mode this.editing = !this.editing
},
toggleHideReadItems() {
this.uiStore.show_only_next_items = !this.uiStore.show_only_next_items
} }
} }
} }

View File

@ -36,10 +36,10 @@
</div> </div>
</form> </form>
<div class="field is-grouped is-grouped-multiline mt-4"> <div class="field is-grouped is-grouped-multiline mt-4">
<div v-for="query in history" :key="query" class="control"> <div v-for="item in history" :key="item" class="control">
<div class="tags has-addons"> <div class="tags has-addons">
<a class="tag" @click="openSearch(query)" v-text="query" /> <a class="tag" @click="openSearch(item)" v-text="item" />
<a class="tag is-delete" @click="removeSearch(query)" /> <a class="tag is-delete" @click="removeSearch(item)" />
</div> </div>
</div> </div>
</div> </div>
@ -131,14 +131,14 @@ export default {
track: ListTracks.name track: ListTracks.name
}, },
results: new Map(), results: new Map(),
search_limit: {}, limit: {},
query: '', query: '',
search_types: SEARCH_TYPES types: SEARCH_TYPES
} }
}, },
computed: { computed: {
expanded() { expanded() {
return this.search_types.length === 1 return this.types.length === 1
}, },
history() { history() {
return this.searchStore.history return this.searchStore.history
@ -152,20 +152,20 @@ export default {
mounted() { mounted() {
this.searchStore.source = this.$route.name this.searchStore.source = this.$route.name
this.query = this.searchStore.query this.query = this.searchStore.query
this.search_limit = PAGE_SIZE this.limit = PAGE_SIZE
this.search() this.search()
}, },
methods: { methods: {
expand(type) { expand(type) {
this.query = this.searchStore.query this.query = this.searchStore.query
this.search_types = [type] this.types = [type]
this.search_limit = -1 this.limit = -1
this.search() this.search()
}, },
openSearch(query) { openSearch(query) {
this.query = query this.query = query
this.search_types = SEARCH_TYPES this.types = SEARCH_TYPES
this.search_limit = PAGE_SIZE this.limit = PAGE_SIZE
this.search() this.search()
}, },
removeSearch(query) { removeSearch(query) {
@ -173,14 +173,14 @@ export default {
}, },
reset() { reset() {
this.results.clear() this.results.clear()
this.search_types.forEach((type) => { this.types.forEach((type) => {
this.results.set(type, new GroupedList()) this.results.set(type, new GroupedList())
}) })
}, },
search(event) { search(event) {
if (event) { if (event) {
this.search_types = SEARCH_TYPES this.types = SEARCH_TYPES
this.search_limit = PAGE_SIZE this.limit = PAGE_SIZE
} }
this.query = this.query.trim() this.query = this.query.trim()
if (!this.query || !this.query.replace(/^query:/u, '')) { if (!this.query || !this.query.replace(/^query:/u, '')) {
@ -188,7 +188,7 @@ export default {
return return
} }
this.reset() this.reset()
this.search_types.forEach((type) => { this.types.forEach((type) => {
this.searchItems(type) this.searchItems(type)
}) })
this.searchStore.add(this.query) this.searchStore.add(this.query)
@ -197,7 +197,7 @@ export default {
const music = type !== 'audiobook' && type !== 'podcast' const music = type !== 'audiobook' && type !== 'podcast'
const kind = music ? 'music' : type const kind = music ? 'music' : type
const parameters = { const parameters = {
limit: this.search_limit, limit: this.limit,
type: music ? type : 'album' type: music ? type : 'album'
} }
if (this.query.startsWith('query:')) { if (this.query.startsWith('query:')) {
@ -216,7 +216,7 @@ export default {
this.$router.push({ name: 'search-spotify' }) this.$router.push({ name: 'search-spotify' })
}, },
show(type) { show(type) {
return this.search_types.includes(type) return this.types.includes(type)
}, },
showAllButton(items) { showAllButton(items) {
return items.total > items.items.length return items.total > items.items.length

View File

@ -19,10 +19,10 @@
</div> </div>
</form> </form>
<div class="field is-grouped is-grouped-multiline mt-4"> <div class="field is-grouped is-grouped-multiline mt-4">
<div v-for="query in history" :key="query" class="control"> <div v-for="item in history" :key="item" class="control">
<div class="tags has-addons"> <div class="tags has-addons">
<a class="tag" @click="openSearch(query)" v-text="query" /> <a class="tag" @click="openSearch(item)" v-text="item" />
<a class="tag is-delete" @click="removeSearch(query)" /> <a class="tag is-delete" @click="removeSearch(item)" />
</div> </div>
</div> </div>
</div> </div>
@ -118,14 +118,14 @@ export default {
track: ListTracksSpotify.name track: ListTracksSpotify.name
}, },
results: new Map(), results: new Map(),
search_parameters: {}, parameters: {},
query: '', query: '',
search_types: SEARCH_TYPES types: SEARCH_TYPES
} }
}, },
computed: { computed: {
expanded() { expanded() {
return this.search_types.length === 1 return this.types.length === 1
}, },
history() { history() {
return this.searchStore.history.filter( return this.searchStore.history.filter(
@ -141,22 +141,22 @@ export default {
mounted() { mounted() {
this.searchStore.source = this.$route.name this.searchStore.source = this.$route.name
this.query = this.searchStore.query this.query = this.searchStore.query
this.search_parameters.limit = PAGE_SIZE this.parameters.limit = PAGE_SIZE
this.search() this.search()
}, },
methods: { methods: {
expand(type) { expand(type) {
this.query = this.searchStore.query this.query = this.searchStore.query
this.search_types = [type] this.types = [type]
this.search_parameters.limit = PAGE_SIZE_EXPANDED this.parameters.limit = PAGE_SIZE_EXPANDED
this.search_parameters.offset = 0 this.parameters.offset = 0
this.search() this.search()
}, },
openSearch(query) { openSearch(query) {
this.query = query this.query = query
this.search_types = SEARCH_TYPES this.types = SEARCH_TYPES
this.search_parameters.limit = PAGE_SIZE this.parameters.limit = PAGE_SIZE
this.search_parameters.offset = 0 this.parameters.offset = 0
this.search() this.search()
}, },
removeSearch(query) { removeSearch(query) {
@ -164,14 +164,14 @@ export default {
}, },
reset() { reset() {
this.results.clear() this.results.clear()
this.search_types.forEach((type) => { this.types.forEach((type) => {
this.results.set(type, { items: [], total: 0 }) this.results.set(type, { items: [], total: 0 })
}) })
}, },
search(event) { search(event) {
if (event) { if (event) {
this.search_types = SEARCH_TYPES this.types = SEARCH_TYPES
this.search_parameters.limit = PAGE_SIZE this.parameters.limit = PAGE_SIZE
} }
this.query = this.query.trim() this.query = this.query.trim()
if (!this.query) { if (!this.query) {
@ -180,7 +180,7 @@ export default {
} }
this.reset() this.reset()
this.searchItems().then((data) => { this.searchItems().then((data) => {
this.search_types.forEach((type) => { this.types.forEach((type) => {
this.results.set(type, data[`${type}s`]) this.results.set(type, data[`${type}s`])
}) })
}) })
@ -188,14 +188,10 @@ export default {
}, },
searchItems() { searchItems() {
return webapi.spotify().then(({ data }) => { return webapi.spotify().then(({ data }) => {
this.search_parameters.market = data.webapi_country this.parameters.market = data.webapi_country
const spotifyApi = new SpotifyWebApi() const spotifyApi = new SpotifyWebApi()
spotifyApi.setAccessToken(data.webapi_token) spotifyApi.setAccessToken(data.webapi_token)
return spotifyApi.search( return spotifyApi.search(this.query, this.types, this.parameters)
this.query,
this.search_types,
this.search_parameters
)
}) })
}, },
searchLibrary() { searchLibrary() {
@ -204,22 +200,22 @@ export default {
}) })
}, },
searchNext({ loaded }) { searchNext({ loaded }) {
const [type] = this.search_types, const [type] = this.types,
items = this.results.get(type) items = this.results.get(type)
this.search_parameters.limit = PAGE_SIZE_EXPANDED this.parameters.limit = PAGE_SIZE_EXPANDED
this.searchItems().then((data) => { this.searchItems().then((data) => {
const [next] = Object.values(data) const [next] = Object.values(data)
items.items.push(...next.items) items.items.push(...next.items)
items.total = next.total items.total = next.total
if (!this.search_parameters.offset) { if (!this.parameters.offset) {
this.search_parameters.offset = 0 this.parameters.offset = 0
} }
this.search_parameters.offset += next.limit this.parameters.offset += next.limit
loaded(next.items.length, PAGE_SIZE_EXPANDED) loaded(next.items.length, PAGE_SIZE_EXPANDED)
}) })
}, },
show(type) { show(type) {
return this.search_types.includes(type) return this.types.includes(type)
}, },
showAllButton(items) { showAllButton(items) {
return items.total > items.items.length return items.total > items.items.length

View File

@ -46,84 +46,61 @@ const TOP_WITH_TABS = 100
export const router = createRouter({ export const router = createRouter({
history: createWebHashHistory(), history: createWebHashHistory(),
routes: [ routes: [
{ { path: '/:all(.*)*', redirect: '/' },
path: '/:all(.*)*', { component: PageAbout, name: 'about', path: '/about' },
redirect: '/' { component: PageAlbum, name: 'music-album', path: '/music/albums/:id' },
},
{
component: PageAbout,
name: 'about',
path: '/about'
},
{
component: PageAlbum,
meta: { show_progress: true },
name: 'music-album',
path: '/music/albums/:id'
},
{ {
component: PageAlbumSpotify, component: PageAlbumSpotify,
meta: { show_progress: true },
name: 'music-spotify-album', name: 'music-spotify-album',
path: '/music/spotify/albums/:id' path: '/music/spotify/albums/:id'
}, },
{ {
component: PageAlbums, component: PageAlbums,
meta: { has_index: true, show_progress: true },
name: 'music-albums', name: 'music-albums',
path: '/music/albums' path: '/music/albums'
}, },
{ {
component: PageArtist, component: PageArtist,
meta: { has_index: true, show_progress: true },
name: 'music-artist', name: 'music-artist',
path: '/music/artists/:id' path: '/music/artists/:id'
}, },
{ {
component: PageArtistSpotify, component: PageArtistSpotify,
meta: { show_progress: true },
name: 'music-spotify-artist', name: 'music-spotify-artist',
path: '/music/spotify/artists/:id' path: '/music/spotify/artists/:id'
}, },
{ {
component: PageArtists, component: PageArtists,
meta: { has_index: true, show_progress: true },
name: 'music-artists', name: 'music-artists',
path: '/music/artists' path: '/music/artists'
}, },
{ {
component: PageArtistTracks, component: PageArtistTracks,
meta: { has_index: true, show_progress: true },
name: 'music-artist-tracks', name: 'music-artist-tracks',
path: '/music/artists/:id/tracks' path: '/music/artists/:id/tracks'
}, },
{ {
component: PageAudiobooksAlbum, component: PageAudiobooksAlbum,
meta: { show_progress: true },
name: 'audiobooks-album', name: 'audiobooks-album',
path: '/audiobooks/albums/:id' path: '/audiobooks/albums/:id'
}, },
{ {
component: PageAudiobooksAlbums, component: PageAudiobooksAlbums,
meta: { has_index: true, show_progress: true },
name: 'audiobooks-albums', name: 'audiobooks-albums',
path: '/audiobooks/albums' path: '/audiobooks/albums'
}, },
{ {
component: PageAudiobooksArtist, component: PageAudiobooksArtist,
meta: { show_progress: true },
name: 'audiobooks-artist', name: 'audiobooks-artist',
path: '/audiobooks/artists/:id' path: '/audiobooks/artists/:id'
}, },
{ {
component: PageAudiobooksArtists, component: PageAudiobooksArtists,
meta: { has_index: true, show_progress: true },
name: 'audiobooks-artists', name: 'audiobooks-artists',
path: '/audiobooks/artists' path: '/audiobooks/artists'
}, },
{ {
component: PageAudiobooksGenres, component: PageAudiobooksGenres,
meta: { has_index: true, show_progress: true },
name: 'audiobooks-genres', name: 'audiobooks-genres',
path: '/audiobooks/genres' path: '/audiobooks/genres'
}, },
@ -139,87 +116,66 @@ export const router = createRouter({
}, },
{ {
component: PageMusic, component: PageMusic,
meta: { show_progress: true },
name: 'music-history', name: 'music-history',
path: '/music/history' path: '/music/history'
}, },
{ {
component: PageMusicRecentlyAdded, component: PageMusicRecentlyAdded,
meta: { show_progress: true },
name: 'music-recently-added', name: 'music-recently-added',
path: '/music/recently-added' path: '/music/recently-added'
}, },
{ {
component: PageMusicRecentlyPlayed, component: PageMusicRecentlyPlayed,
meta: { show_progress: true },
name: 'music-recently-played', name: 'music-recently-played',
path: '/music/recently-played' path: '/music/recently-played'
}, },
{ {
component: PageMusicSpotify, component: PageMusicSpotify,
meta: { show_progress: true },
name: 'music-spotify', name: 'music-spotify',
path: '/music/spotify' path: '/music/spotify'
}, },
{ {
component: PageMusicSpotifyFeaturedPlaylists, component: PageMusicSpotifyFeaturedPlaylists,
meta: { show_progress: true },
name: 'music-spotify-featured-playlists', name: 'music-spotify-featured-playlists',
path: '/music/spotify/featured-playlists' path: '/music/spotify/featured-playlists'
}, },
{ {
component: PageMusicSpotifyNewReleases, component: PageMusicSpotifyNewReleases,
meta: { show_progress: true },
name: 'music-spotify-new-releases', name: 'music-spotify-new-releases',
path: '/music/spotify/new-releases' path: '/music/spotify/new-releases'
}, },
{ {
component: PageComposerAlbums, component: PageComposerAlbums,
meta: { show_progress: true },
name: 'music-composer-albums', name: 'music-composer-albums',
path: '/music/composers/:name/albums' path: '/music/composers/:name/albums'
}, },
{ {
component: PageComposerTracks, component: PageComposerTracks,
meta: { show_progress: true },
name: 'music-composer-tracks', name: 'music-composer-tracks',
path: '/music/composers/:name/tracks' path: '/music/composers/:name/tracks'
}, },
{ {
component: PageComposers, component: PageComposers,
meta: { has_index: true, show_progress: true },
name: 'music-composers', name: 'music-composers',
path: '/music/composers' path: '/music/composers'
}, },
{ { component: PageFiles, name: 'files', path: '/files' },
component: PageFiles,
meta: { show_progress: true },
name: 'files',
path: '/files'
},
{ {
component: PageGenreAlbums, component: PageGenreAlbums,
meta: { has_index: true, show_progress: true },
name: 'genre-albums', name: 'genre-albums',
path: '/genres/:name/albums' path: '/genres/:name/albums'
}, },
{ {
component: PageGenreTracks, component: PageGenreTracks,
meta: { has_index: true, show_progress: true },
name: 'genre-tracks', name: 'genre-tracks',
path: '/genres/:name/tracks' path: '/genres/:name/tracks'
}, },
{ {
component: PageGenres, component: PageGenres,
meta: { has_index: true, show_progress: true },
name: 'music-genres', name: 'music-genres',
path: '/music/genres' path: '/music/genres'
}, },
{ { component: PageNowPlaying, name: 'now-playing', path: '/now-playing' },
component: PageNowPlaying,
name: 'now-playing',
path: '/now-playing'
},
{ {
name: 'playlists', name: 'playlists',
path: '/playlists', path: '/playlists',
@ -227,37 +183,23 @@ export const router = createRouter({
}, },
{ {
component: PagePlaylistFolder, component: PagePlaylistFolder,
meta: { show_progress: true },
name: 'playlist-folder', name: 'playlist-folder',
path: '/playlists/:id' path: '/playlists/:id'
}, },
{ {
component: PagePlaylistTracks, component: PagePlaylistTracks,
meta: { show_progress: true },
name: 'playlist', name: 'playlist',
path: '/playlists/:id/tracks' path: '/playlists/:id/tracks'
}, },
{ {
component: PagePlaylistTracksSpotify, component: PagePlaylistTracksSpotify,
meta: { show_progress: true },
name: 'playlist-spotify', name: 'playlist-spotify',
path: '/playlists/spotify/:id/tracks' path: '/playlists/spotify/:id/tracks'
}, },
{ { component: PagePodcast, name: 'podcast', path: '/podcasts/:id' },
component: PagePodcast, { component: PagePodcasts, name: 'podcasts', path: '/podcasts' },
meta: { show_progress: true },
name: 'podcast',
path: '/podcasts/:id'
},
{
component: PagePodcasts,
meta: { show_progress: true },
name: 'podcasts',
path: '/podcasts'
},
{ {
component: PageRadioStreams, component: PageRadioStreams,
meta: { show_progress: true },
name: 'radio', name: 'radio',
path: '/radio' path: '/radio'
}, },
@ -328,13 +270,13 @@ export const router = createRouter({
router.beforeEach((to, from, next) => { router.beforeEach((to, from, next) => {
const uiStore = useUIStore() const uiStore = useUIStore()
if (uiStore.show_burger_menu) { if (uiStore.showBurgerMenu) {
uiStore.show_burger_menu = false uiStore.showBurgerMenu = false
next(false) next(false)
return return
} }
if (uiStore.show_player_menu) { if (uiStore.showPlayerMenu) {
uiStore.show_player_menu = false uiStore.showPlayerMenu = false
next(false) next(false)
return return
} }

View File

@ -1,8 +1,13 @@
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
export const useLyricsStore = defineStore('LyricsStore', { export const useLyricsStore = defineStore('LyricsStore', {
actions: {
toggle() {
this.active = !this.active
}
},
state: () => ({ state: () => ({
content: [], content: [],
pane: false active: false
}) })
}) })

View File

@ -4,7 +4,7 @@ export const useNotificationsStore = defineStore('NotificationsStore', {
actions: { actions: {
add(notification) { add(notification) {
const newNotification = { const newNotification = {
id: this.next_id++, id: this.nextId++,
text: notification.text, text: notification.text,
timeout: notification.timeout, timeout: notification.timeout,
topic: notification.topic, topic: notification.topic,
@ -33,8 +33,5 @@ export const useNotificationsStore = defineStore('NotificationsStore', {
} }
} }
}, },
state: () => ({ state: () => ({ list: [], nextId: 1 })
list: [],
next_id: 1
})
}) })

View File

@ -1,6 +1,13 @@
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
export const usePlayerStore = defineStore('PlayerStore', { export const usePlayerStore = defineStore('PlayerStore', {
getters: {
isPlaying: (state) => state.state === 'play',
isRepeatAll: (state) => state.repeat === 'all',
isRepeatOff: (state) => state.repeat === 'off',
isRepeatSingle: (state) => state.repeat === 'single',
isStopped: (state) => state.state === 'stop'
},
state: () => ({ state: () => ({
consume: false, consume: false,
item_id: 0, item_id: 0,

View File

@ -1,4 +1,5 @@
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
import { useConfigurationStore } from '@/stores/configuration'
import { usePlayerStore } from '@/stores/player' import { usePlayerStore } from '@/stores/player'
export const useQueueStore = defineStore('QueueStore', { export const useQueueStore = defineStore('QueueStore', {
@ -6,6 +7,19 @@ export const useQueueStore = defineStore('QueueStore', {
current(state) { current(state) {
const player = usePlayerStore() const player = usePlayerStore()
return state.items.find((item) => item.id === player.item_id) ?? {} return state.items.find((item) => item.id === player.item_id) ?? {}
},
isEmpty(state) {
return state.items.length === 0
},
isPauseAllowed(state) {
return state.current && state.current.data_kind !== 'pipe'
},
isSavingAllowed(state) {
const configuration = useConfigurationStore()
return (
configuration.allow_modifying_stored_playlists &&
configuration.default_playlist_directory
)
} }
}, },
state: () => ({ state: () => ({

View File

@ -1,6 +1,11 @@
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
export const useServicesStore = defineStore('ServicesStore', { export const useServicesStore = defineStore('ServicesStore', {
actions: {
isSpotifyEnabled() {
return this.spotify.webapi_token_valid
}
},
state: () => ({ state: () => ({
lastfm: {}, lastfm: {},
spotify: {} spotify: {}

View File

@ -1,6 +1,23 @@
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
export const useUIStore = defineStore('UIStore', { export const useUIStore = defineStore('UIStore', {
actions: {
hideMenus() {
this.showBurgerMenu = false
this.showPlayerMenu = false
},
toggleBurgerMenu() {
this.showPlayerMenu = false
this.showBurgerMenu = !this.showBurgerMenu
},
togglePlayerMenu() {
this.showBurgerMenu = false
this.showPlayerMenu = !this.showPlayerMenu
},
toggleHideReadItems() {
this.hideReadItems = !this.hideReadItems
}
},
state: () => ({ state: () => ({
albums_sort: 1, albums_sort: 1,
artist_albums_sort: 1, artist_albums_sort: 1,
@ -8,11 +25,11 @@ export const useUIStore = defineStore('UIStore', {
artists_sort: 1, artists_sort: 1,
composer_tracks_sort: 1, composer_tracks_sort: 1,
genre_tracks_sort: 1, genre_tracks_sort: 1,
hide_singles: false, hideReadItems: false,
hide_spotify: false, hideSingles: false,
show_burger_menu: false, hideSpotify: false,
show_only_next_items: false, showBurgerMenu: false,
show_player_menu: false, showPlayerMenu: false,
show_update_dialog: false showUpdateDialog: false
}) })
}) })