[web] Change how data is loaded

This commit is contained in:
Alain Nussbaumer 2025-04-26 21:31:03 +02:00
parent 1ce771c900
commit bbf7c28349
50 changed files with 332 additions and 360 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

@ -99,7 +99,7 @@ export default {
connect() { connect() {
webapi webapi
.config() .config()
.then(({ data }) => { .then((data) => {
this.configurationStore.$state = data this.configurationStore.$state = data
this.uiStore.hideSingles = data.hide_singles this.uiStore.hideSingles = data.hide_singles
document.title = data.library_name document.title = data.library_name
@ -224,22 +224,22 @@ export default {
} }
}, },
updateLastfm() { updateLastfm() {
webapi.lastfm().then(({ data }) => { webapi.lastfm().then((data) => {
this.servicesStore.lastfm = data this.servicesStore.lastfm = data
}) })
}, },
updateLibraryStats() { updateLibraryStats() {
webapi.library_stats().then(({ data }) => { webapi.library_stats().then((data) => {
this.libraryStore.$state = data this.libraryStore.$state = data
}) })
webapi.library_count('scan_kind is rss').then(({ data }) => { webapi.library_count('scan_kind is rss').then((data) => {
this.libraryStore.rss = data this.libraryStore.rss = data
}) })
}, },
updateLyrics() { updateLyrics() {
const track = this.queueStore.current const track = this.queueStore.current
if (track?.track_id) { if (track?.track_id) {
webapi.library_track(track.track_id).then(({ data }) => { webapi.library_track(track.track_id).then((data) => {
this.lyricsStore.lyrics = data.lyrics this.lyricsStore.lyrics = data.lyrics
}) })
} else { } else {
@ -247,35 +247,35 @@ export default {
} }
}, },
updateOutputs() { updateOutputs() {
webapi.outputs().then(({ data }) => { webapi.outputs().then((data) => {
this.outputsStore.outputs = data.outputs this.outputsStore.outputs = data.outputs
}) })
}, },
updatePairing() { updatePairing() {
webapi.pairing().then(({ data }) => { webapi.pairing().then((data) => {
this.remotesStore.$state = data this.remotesStore.$state = data
this.pairingActive = data.active this.pairingActive = data.active
}) })
}, },
updatePlayerStatus() { updatePlayerStatus() {
webapi.player_status().then(({ data }) => { webapi.player_status().then((data) => {
this.playerStore.$state = data this.playerStore.$state = data
this.updateLyrics() this.updateLyrics()
}) })
}, },
updateQueue() { updateQueue() {
webapi.queue().then(({ data }) => { webapi.queue().then((data) => {
this.queueStore.$state = data this.queueStore.$state = data
this.updateLyrics() this.updateLyrics()
}) })
}, },
updateSettings() { updateSettings() {
webapi.settings().then(({ data }) => { webapi.settings().then((data) => {
this.settingsStore.$state = data this.settingsStore.$state = data
}) })
}, },
updateSpotify() { updateSpotify() {
webapi.spotify().then(({ data }) => { webapi.spotify().then((data) => {
this.servicesStore.spotify = data this.servicesStore.spotify = data
if (this.timerId > 0) { if (this.timerId > 0) {
window.clearTimeout(this.timerId) window.clearTimeout(this.timerId)

View File

@ -18,39 +18,19 @@
:media-kind="mediaKind" :media-kind="mediaKind"
:show="showDetailsModal" :show="showDetailsModal"
@close="showDetailsModal = false" @close="showDetailsModal = false"
@remove-podcast="openRemovePodcastDialog()" @play-count-changed="playCountChanged"
@play-count-changed="onPlayCountChange()" @podcast-deleted="podcastDeleted"
/> />
<modal-dialog
:actions="actions"
:show="showRemovePodcastModal"
:title="$t('page.podcast.remove-podcast')"
@cancel="showRemovePodcastModal = false"
@remove="removePodcast"
>
<template #content>
<i18n-t keypath="list.albums.info" tag="p" scope="global">
<template #separator>
<br />
</template>
<template #name>
<b v-text="playlistToRemove.name" />
</template>
</i18n-t>
</template>
</modal-dialog>
</template> </template>
<script> <script>
import ListItem from '@/components/ListItem.vue' import ListItem from '@/components/ListItem.vue'
import ModalDialog from '@/components/ModalDialog.vue'
import ModalDialogAlbum from '@/components/ModalDialogAlbum.vue' import ModalDialogAlbum from '@/components/ModalDialogAlbum.vue'
import { useSettingsStore } from '@/stores/settings' import { useSettingsStore } from '@/stores/settings'
import webapi from '@/webapi'
export default { export default {
name: 'ListAlbums', name: 'ListAlbums',
components: { ListItem, ModalDialog, ModalDialogAlbum }, components: { ListItem, ModalDialogAlbum },
props: { props: {
items: { required: true, type: Object }, items: { required: true, type: Object },
mediaKind: { default: '', type: String } mediaKind: { default: '', type: String }
@ -61,19 +41,11 @@ export default {
}, },
data() { data() {
return { return {
playlistToRemove: {},
selectedItem: {}, selectedItem: {},
showDetailsModal: false, showDetailsModal: false
showRemovePodcastModal: false
} }
}, },
computed: { computed: {
actions() {
return [
{ handler: 'cancel', icon: 'cancel', key: 'page.podcast.cancel' },
{ handler: 'remove', icon: 'delete', key: 'page.podcast.remove' }
]
},
media_kind_resolved() { media_kind_resolved() {
return this.mediaKind || this.selectedItem.media_kind return this.mediaKind || this.selectedItem.media_kind
} }
@ -102,27 +74,11 @@ export default {
this.selectedItem = item this.selectedItem = item
this.showDetailsModal = true this.showDetailsModal = true
}, },
openRemovePodcastDialog() { playCountChanged() {
webapi
.library_album_tracks(this.selectedItem.id, { limit: 1 })
.then(({ data: album }) => {
webapi.library_track_playlists(album.items[0].id).then(({ data }) => {
;[this.playlistToRemove] = data.items.filter(
(playlist) => playlist.type === 'rss'
)
this.showRemovePodcastModal = true
this.showDetailsModal = false
})
})
},
onPlayCountChange() {
this.$emit('play-count-changed') this.$emit('play-count-changed')
}, },
removePodcast() { podcastDeleted() {
this.showRemovePodcastModal = false this.$emit('podcast-deleted')
webapi.library_playlist_delete(this.playlistToRemove.id).then(() => {
this.$emit('podcast-deleted')
})
} }
} }
} }

View File

@ -6,13 +6,15 @@
@close="$emit('close')" @close="$emit('close')"
> >
<template #content> <template #content>
<control-url-field <form @submit.prevent="add">
icon="rss" <control-url-field
:help="$t('dialog.add.rss.help')" icon="rss"
:loading="loading" :help="$t('dialog.add.rss.help')"
:placeholder="$t('dialog.add.rss.placeholder')" :loading="loading"
@input="onUrlChange" :placeholder="$t('dialog.add.rss.placeholder')"
/> @input="onUrlChange"
/>
</form>
</template> </template>
</modal-dialog> </modal-dialog>
</template> </template>
@ -56,9 +58,10 @@ export default {
webapi webapi
.library_add(this.url) .library_add(this.url)
.then(() => { .then(() => {
this.$emit('close')
this.$emit('podcast-added') this.$emit('podcast-added')
this.$emit('close')
this.url = '' this.url = ''
this.loading = false
}) })
.catch(() => { .catch(() => {
this.loading = false this.loading = false

View File

@ -5,28 +5,69 @@
:show="show" :show="show"
@close="$emit('close')" @close="$emit('close')"
/> />
<modal-dialog
:actions="actions"
:show="showRemovePodcastModal"
:title="$t('dialog.podcast.remove.title')"
@close="showRemovePodcastModal = false"
@remove="removePodcast"
>
<template #content>
<i18n-t keypath="dialog.podcast.remove.info" tag="p" scope="global">
<template #separator>
<br />
</template>
<template #name>
<b v-text="item.name" />
</template>
</i18n-t>
</template>
</modal-dialog>
</template> </template>
<script> <script>
import ModalDialog from '@/components/ModalDialog.vue'
import ModalDialogPlayable from '@/components/ModalDialogPlayable.vue' import ModalDialogPlayable from '@/components/ModalDialogPlayable.vue'
import webapi from '@/webapi' import webapi from '@/webapi'
export default { export default {
name: 'ModalDialogAlbum', name: 'ModalDialogAlbum',
components: { ModalDialogPlayable }, components: { ModalDialog, ModalDialogPlayable },
props: { props: {
item: { required: true, type: Object }, item: { required: true, type: Object },
mediaKind: { default: '', type: String }, mediaKind: { default: '', type: String },
show: Boolean show: Boolean
}, },
emits: ['close', 'remove-podcast', 'play-count-changed'], emits: ['close', 'play-count-changed', 'podcast-deleted'],
data() {
return {
showRemovePodcastModal: false
}
},
computed: { computed: {
actions() {
return [
{
handler: this.cancel,
icon: 'cancel',
key: this.$t('actions.cancel')
},
{
handler: this.removePodcast,
icon: 'delete',
key: this.$t('actions.remove')
}
]
},
buttons() { buttons() {
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.markAsPlayed, key: 'actions.mark-as-played' }, { handler: this.markAsPlayed, key: 'actions.mark-as-played' },
{ handler: this.removePodcast, key: 'actions.remove-podcast' } {
handler: this.openRemovePodcastDialog,
key: 'actions.remove'
}
] ]
} }
return [{ handler: this.markAsPlayed, key: 'actions.mark-as-played' }] return [{ handler: this.markAsPlayed, key: 'actions.mark-as-played' }]
@ -70,6 +111,9 @@ export default {
} }
}, },
methods: { methods: {
cancel() {
this.showRemovePodcastModal = false
},
markAsPlayed() { markAsPlayed() {
webapi webapi
.library_album_track_update(this.item.id, { play_count: 'played' }) .library_album_track_update(this.item.id, { play_count: 'played' })
@ -92,8 +136,21 @@ export default {
}) })
} }
}, },
openRemovePodcastDialog() {
this.showRemovePodcastModal = true
this.showDetailsModal = false
},
removePodcast() { removePodcast() {
this.$emit('remove-podcast') this.showRemovePodcastModal = false
webapi.library_album_tracks(this.item.id, { limit: 1 }).then((album) => {
webapi.library_track_playlists(album.items[0].id).then((data) => {
const { id } = data.items.find((item) => item.type === 'rss')
webapi.library_playlist_delete(id).then(() => {
this.$emit('podcast-deleted')
this.$emit('close')
})
})
})
} }
} }
} }

View File

@ -76,7 +76,7 @@ export default {
key: 'property.quality', key: 'property.quality',
value: this.$t('dialog.track.quality-value', { value: this.$t('dialog.track.quality-value', {
bitrate: this.item.bitrate, bitrate: this.item.bitrate,
channels: this.$t('count.channels', this.item.channels), channels: this.$t('data.channels', this.item.channels),
format: this.item.type, format: this.item.type,
samplerate: this.item.samplerate samplerate: this.item.samplerate
}) })

View File

@ -68,7 +68,7 @@ export default {
this.item.data_kind !== 'spotify' && this.item.data_kind !== 'spotify' &&
this.$t('dialog.track.quality-value', { this.$t('dialog.track.quality-value', {
bitrate: this.item.bitrate, bitrate: this.item.bitrate,
channels: this.$t('count.channels', this.item.channels), channels: this.$t('data.channels', this.item.channels),
format: this.item.type, format: this.item.type,
samplerate: this.item.samplerate samplerate: this.item.samplerate
}) })

View File

@ -15,7 +15,6 @@
"pair": "Remote paaren", "pair": "Remote paaren",
"play": "Spielen", "play": "Spielen",
"remove": "Entfernen", "remove": "Entfernen",
"remove-podcast": "Entferne podcast",
"rescan": "Neu einlesen", "rescan": "Neu einlesen",
"save": "Speichern", "save": "Speichern",
"send": "Senden", "send": "Senden",
@ -24,7 +23,7 @@
"update": "Neu einlesen", "update": "Neu einlesen",
"verify": "Verifizieren" "verify": "Verifizieren"
}, },
"count": { "data": {
"albums": "{count} Album|{count} Album|{count} Alben", "albums": "{count} Album|{count} Album|{count} Alben",
"artists": "{count} Künstler", "artists": "{count} Künstler",
"audiobooks": "{count} Hörbuch|{count} Hörbuch|{count} Hörbücher", "audiobooks": "{count} Hörbuch|{count} Hörbuch|{count} Hörbücher",
@ -35,9 +34,7 @@
"playlists": "{count} Playlist|{count} Playlisten", "playlists": "{count} Playlist|{count} Playlisten",
"podcasts": "{count} Podcast|{count} Podcasts", "podcasts": "{count} Podcast|{count} Podcasts",
"stations": "{count} Station|{count} Station|{count} Stationen", "stations": "{count} Station|{count} Station|{count} Stationen",
"tracks": "{count} Track|{count} Track|{count} Tracks" "tracks": "{count} Track|{count} Track|{count} Tracks",
},
"data": {
"kind": { "kind": {
"file": "Datei", "file": "Datei",
"url": "URL", "url": "URL",
@ -60,6 +57,12 @@
"title": "Stream hinzufügen" "title": "Stream hinzufügen"
} }
}, },
"podcast": {
"remove": {
"title": "Podcast enfernen",
"info": "Permanently remove this podcast from your library?{separator}(This will also remove the RSS playlist {name})"
}
},
"playlist": { "playlist": {
"save": { "save": {
"playlist-name": "Playlistname", "playlist-name": "Playlistname",
@ -68,14 +71,14 @@
} }
}, },
"queue-item": { "queue-item": {
"quality-value": "{format} {'|'} {samplerate} Hz {'|'} {channels} {'|'} {bitrate} kbit/s" "quality-value": "{format} {'|'} {samplerate} Hz {'|'} @:data.channels {'|'} {bitrate} kbit/s"
}, },
"remote-pairing": { "remote-pairing": {
"pairing-code": "Pairing-Code", "pairing-code": "Pairing-Code",
"title": "Remote-Paarungs-Anfrage" "title": "Remote-Paarungs-Anfrage"
}, },
"track": { "track": {
"quality-value": "{format} {'|'} {samplerate} Hz {'|'} {channels} {'|'} {bitrate} kbit/s", "quality-value": "{format} {'|'} {samplerate} Hz {'|'} @:data.channels {'|'} {bitrate} kbit/s",
"rating-value": "{rating} / 10" "rating-value": "{rating} / 10"
}, },
"update": { "update": {
@ -214,9 +217,6 @@
"playlists": { "playlists": {
"title": "{name}|Playlisten" "title": "{name}|Playlisten"
}, },
"podcast": {
"remove-info": "Diesen Podcast dauerhaft aus der Bibliothek löschen?{separator}(Damit wird auch die RSS-Playliste {name} gelöscht)"
},
"podcasts": { "podcasts": {
"new-episodes": "Neue Episoden", "new-episodes": "Neue Episoden",
"title": "Podcasts" "title": "Podcasts"

View File

@ -15,7 +15,6 @@
"pair": "Pair Remote", "pair": "Pair Remote",
"play": "Play", "play": "Play",
"remove": "Remove", "remove": "Remove",
"remove-podcast": "Remove podcast",
"rescan": "Rescan", "rescan": "Rescan",
"save": "Save", "save": "Save",
"send": "Send", "send": "Send",
@ -24,7 +23,7 @@
"update": "Update", "update": "Update",
"verify": "Verify" "verify": "Verify"
}, },
"count": { "data": {
"albums": "{count} album|{count} album|{count} albums", "albums": "{count} album|{count} album|{count} albums",
"artists": "{count} artist|{count} artist|{count} artists", "artists": "{count} artist|{count} artist|{count} artists",
"audiobooks": "{count} audiobook|{count} audiobook|{count} audiobooks", "audiobooks": "{count} audiobook|{count} audiobook|{count} audiobooks",
@ -35,9 +34,7 @@
"playlists": "{count} playlist|{count} playlist|{count} playlists", "playlists": "{count} playlist|{count} playlist|{count} playlists",
"podcasts": "{count} podcast|{count} podcast|{count} podcasts", "podcasts": "{count} podcast|{count} podcast|{count} podcasts",
"stations": "{count} station|{count} station|{count} stations", "stations": "{count} station|{count} station|{count} stations",
"tracks": "{count} track|{count} track|{count} tracks" "tracks": "{count} track|{count} track|{count} tracks",
},
"data": {
"kind": { "kind": {
"file": "File", "file": "File",
"url": "URL", "url": "URL",
@ -60,6 +57,12 @@
"title": "Add stream" "title": "Add stream"
} }
}, },
"podcast": {
"remove": {
"title": "Delete the podcast",
"info": "Permanently remove this podcast from your library?{separator}(This will also remove the RSS playlist {name})"
}
},
"playlist": { "playlist": {
"save": { "save": {
"playlist-name": "Playlist name", "playlist-name": "Playlist name",
@ -68,14 +71,14 @@
} }
}, },
"queue-item": { "queue-item": {
"quality-value": "{format} {'|'} {samplerate} Hz {'|'} @:count.channels {'|'} {bitrate} kbit/s" "quality-value": "{format} {'|'} {samplerate} Hz {'|'} @:data.channels {'|'} {bitrate} kbit/s"
}, },
"remote-pairing": { "remote-pairing": {
"pairing-code": "Pairing code", "pairing-code": "Pairing code",
"title": "Remote pairing request" "title": "Remote pairing request"
}, },
"track": { "track": {
"quality-value": "{format} {'|'} {samplerate} Hz {'|'} @:count.channels {'|'} {bitrate} kbit/s", "quality-value": "{format} {'|'} {samplerate} Hz {'|'} @:data.channels {'|'} {bitrate} kbit/s",
"rating-value": "{rating} / 10" "rating-value": "{rating} / 10"
}, },
"update": { "update": {
@ -214,9 +217,6 @@
"playlists": { "playlists": {
"title": "{name}|Playlists" "title": "{name}|Playlists"
}, },
"podcast": {
"remove-info": "Permanently remove this podcast from your library?{separator}(This will also remove the RSS playlist {name})"
},
"podcasts": { "podcasts": {
"new-episodes": "New Episodes", "new-episodes": "New Episodes",
"title": "Podcasts" "title": "Podcasts"

View File

@ -15,7 +15,6 @@
"pair": "Jumeler la télécommande", "pair": "Jumeler la télécommande",
"play": "Lire", "play": "Lire",
"remove": "Supprimer", "remove": "Supprimer",
"remove-podcast": "Supprimer le podcast",
"rescan": "Analyser", "rescan": "Analyser",
"save": "Enregistrer", "save": "Enregistrer",
"send": "Envoyer", "send": "Envoyer",
@ -24,7 +23,7 @@
"update": "Actualiser", "update": "Actualiser",
"verify": "Vérifier" "verify": "Vérifier"
}, },
"count": { "data": {
"albums": "{count} album|{count} album|{count} albums", "albums": "{count} album|{count} album|{count} albums",
"artists": "{count} artiste|{count} artiste|{count} artistes", "artists": "{count} artiste|{count} artiste|{count} artistes",
"audiobooks": "{count} livre audio|{count} livre audio|{count} livres audio", "audiobooks": "{count} livre audio|{count} livre audio|{count} livres audio",
@ -35,9 +34,7 @@
"playlists": "{count} liste de lecture|{count} liste de lecture|{count} listes de lecture", "playlists": "{count} liste de lecture|{count} liste de lecture|{count} listes de lecture",
"podcasts": "{count} podcast|{count} podcast|{count} podcasts", "podcasts": "{count} podcast|{count} podcast|{count} podcasts",
"stations": "{count} station|{count} station|{count} stations", "stations": "{count} station|{count} station|{count} stations",
"tracks": "{count} piste|{count} piste|{count} pistes" "tracks": "{count} piste|{count} piste|{count} pistes",
},
"data": {
"kind": { "kind": {
"file": "Fichier", "file": "Fichier",
"url": "URL", "url": "URL",
@ -60,6 +57,12 @@
"title": "Ajouter un flux" "title": "Ajouter un flux"
} }
}, },
"podcast": {
"remove": {
"title": "Supprimer le podcast",
"info": "Supprimer ce podcast de manière permanente de la bibliothèque ?{separator}(Cela supprimera également la liste de lecture RSS {name})"
}
},
"playlist": { "playlist": {
"save": { "save": {
"playlist-name": "Nom de la liste de lecture", "playlist-name": "Nom de la liste de lecture",
@ -68,14 +71,14 @@
} }
}, },
"queue-item": { "queue-item": {
"quality-value": "{format} {'|'} {samplerate} Hz {'|'} {channels} {'|'} {bitrate} kbit/s" "quality-value": "{format} {'|'} {samplerate} Hz {'|'} @:data.channels {'|'} {bitrate} kbit/s"
}, },
"remote-pairing": { "remote-pairing": {
"pairing-code": "Code de jumelage", "pairing-code": "Code de jumelage",
"title": "Demande de jumelage de télécommande" "title": "Demande de jumelage de télécommande"
}, },
"track": { "track": {
"quality-value": "{format} {'|'} {samplerate} Hz {'|'} {channels} {'|'} {bitrate} kbit/s", "quality-value": "{format} {'|'} {samplerate} Hz {'|'} @:data.channels {'|'} {bitrate} kbit/s",
"rating-value": "{rating} / 10" "rating-value": "{rating} / 10"
}, },
"update": { "update": {
@ -214,9 +217,6 @@
"playlists": { "playlists": {
"title": "{name}|Listes de lecture" "title": "{name}|Listes de lecture"
}, },
"podcast": {
"remove-info": "Supprimer ce podcast de manière permanente de la bibliothèque ?{separator}(Cela supprimera également la liste de lecture RSS {name})"
},
"podcasts": { "podcasts": {
"new-episodes": "Nouveaux épisodes", "new-episodes": "Nouveaux épisodes",
"title": "Podcasts" "title": "Podcasts"

View File

@ -15,7 +15,6 @@
"pair": "遥控配对", "pair": "遥控配对",
"play": "播放", "play": "播放",
"remove": "移除", "remove": "移除",
"remove-podcast": "移除播客",
"rescan": "重新扫描", "rescan": "重新扫描",
"save": "保存", "save": "保存",
"send": "发送", "send": "发送",
@ -24,7 +23,7 @@
"update": "更新", "update": "更新",
"verify": "验证" "verify": "验证"
}, },
"count": { "data": {
"albums": "{count} 张专辑|{count} 张专辑", "albums": "{count} 张专辑|{count} 张专辑",
"artists": "{count} 位艺人|{count} 位艺人", "artists": "{count} 位艺人|{count} 位艺人",
"audiobooks": "{count} 个有声读物|{count} 个有声读物", "audiobooks": "{count} 个有声读物|{count} 个有声读物",
@ -35,9 +34,7 @@
"playlists": "{count} 个播放列表|{count} 个播放列表", "playlists": "{count} 个播放列表|{count} 个播放列表",
"podcasts": "{count} 个播客|{count} 个播客", "podcasts": "{count} 个播客|{count} 个播客",
"stations": "{count} 个电台|{count} 个电台", "stations": "{count} 个电台|{count} 个电台",
"tracks": "{count} 只曲目|{count} 只曲目" "tracks": "{count} 只曲目|{count} 只曲目",
},
"data": {
"kind": { "kind": {
"file": "文件", "file": "文件",
"url": "链接", "url": "链接",
@ -60,6 +57,12 @@
"title": "添加流" "title": "添加流"
} }
}, },
"podcast": {
"remove": {
"title": "移除播客",
"info": "从资料库中永久移除该播客?{separator}(这也将移除该播客RSS列表 {name})"
}
},
"playlist": { "playlist": {
"save": { "save": {
"playlist-name": "播放列表名称", "playlist-name": "播放列表名称",
@ -68,14 +71,14 @@
} }
}, },
"queue-item": { "queue-item": {
"quality-value": "{format} {'|'} {samplerate} Hz {'|'} {channels} {'|'} {bitrate} kbit/s" "quality-value": "{format} {'|'} {samplerate} Hz {'|'} @:data.channels {'|'} {bitrate} kbit/s"
}, },
"remote-pairing": { "remote-pairing": {
"pairing-code": "配对码", "pairing-code": "配对码",
"title": "请求遥控配对" "title": "请求遥控配对"
}, },
"track": { "track": {
"quality-value": "{format} {'|'} {samplerate} Hz {'|'} {channels} {'|'} {bitrate} kbit/s", "quality-value": "{format} {'|'} {samplerate} Hz {'|'} @:data.channels {'|'} {bitrate} kbit/s",
"rating-value": "{rating} / 10" "rating-value": "{rating} / 10"
}, },
"update": { "update": {
@ -214,9 +217,6 @@
"playlists": { "playlists": {
"title": "{name}|播放列表" "title": "{name}|播放列表"
}, },
"podcast": {
"remove-info": "从资料库中永久移除该播客?{separator}(这也将移除该播客RSS列表 {name})"
},
"podcasts": { "podcasts": {
"new-episodes": "最新单集", "new-episodes": "最新单集",
"title": "播客" "title": "播客"

View File

@ -15,7 +15,6 @@
"pair": "遙控配對", "pair": "遙控配對",
"play": "播放", "play": "播放",
"remove": "移除", "remove": "移除",
"remove-podcast": "移除Podcast",
"rescan": "重新掃描", "rescan": "重新掃描",
"save": "儲存", "save": "儲存",
"send": "發送", "send": "發送",
@ -24,7 +23,7 @@
"update": "更新", "update": "更新",
"verify": "驗證" "verify": "驗證"
}, },
"count": { "data": {
"albums": "{count} 張專輯|{count} 張專輯", "albums": "{count} 張專輯|{count} 張專輯",
"artists": "{count} 位藝人|{count} 位藝人", "artists": "{count} 位藝人|{count} 位藝人",
"audiobooks": "{count} 個有聲書|{count} 個有聲書", "audiobooks": "{count} 個有聲書|{count} 個有聲書",
@ -35,9 +34,7 @@
"playlists": "{count} 個播放列表|{count} 個播放列表", "playlists": "{count} 個播放列表|{count} 個播放列表",
"podcasts": "{count} 個Podcast|{count} 個Podcast", "podcasts": "{count} 個Podcast|{count} 個Podcast",
"stations": "{count} 個電台|{count} 個電台", "stations": "{count} 個電台|{count} 個電台",
"tracks": "{count} 首曲目|{count} 首曲目" "tracks": "{count} 首曲目|{count} 首曲目",
},
"data": {
"kind": { "kind": {
"file": "文件", "file": "文件",
"url": "鏈接", "url": "鏈接",
@ -60,6 +57,12 @@
"title": "新增串流" "title": "新增串流"
} }
}, },
"podcast": {
"remove": {
"title": "移除Podcast",
"info": "從資料庫中永久移除該Podcast{separator}(這也將移除該PodcastRSS列表 {name})"
}
},
"playlist": { "playlist": {
"save": { "save": {
"playlist-name": "播放列表名稱", "playlist-name": "播放列表名稱",
@ -68,14 +71,14 @@
} }
}, },
"queue-item": { "queue-item": {
"quality-value": "{format} {'|'} {samplerate} Hz {'|'} {channels} {'|'} {bitrate} kbit/s" "quality-value": "{format} {'|'} {samplerate} Hz {'|'} @:data.channels {'|'} {bitrate} kbit/s"
}, },
"remote-pairing": { "remote-pairing": {
"pairing-code": "配對碼", "pairing-code": "配對碼",
"title": "請求遙控配對" "title": "請求遙控配對"
}, },
"track": { "track": {
"quality-value": "{format} {'|'} {samplerate} Hz {'|'} {channels} {'|'} {bitrate} kbit/s", "quality-value": "{format} {'|'} {samplerate} Hz {'|'} @:data.channels {'|'} {bitrate} kbit/s",
"rating-value": "{rating} / 10" "rating-value": "{rating} / 10"
}, },
"update": { "update": {
@ -214,9 +217,6 @@
"playlists": { "playlists": {
"title": "{name}|播放列表" "title": "{name}|播放列表"
}, },
"podcast": {
"remove-info": "從資料庫中永久移除該Podcast{separator}(這也將移除該PodcastRSS列表 {name})"
},
"podcasts": { "podcasts": {
"new-episodes": "最新單集", "new-episodes": "最新單集",
"title": "Podcast" "title": "Podcast"

View File

@ -46,8 +46,8 @@ export default {
webapi.library_album_tracks(to.params.id) webapi.library_album_tracks(to.params.id)
]).then(([album, tracks]) => { ]).then(([album, tracks]) => {
next((vm) => { next((vm) => {
vm.album = album.data vm.album = album
vm.tracks = new GroupedList(tracks.data, { vm.tracks = new GroupedList(tracks, {
criteria: [{ field: 'disc_number', type: Number }], criteria: [{ field: 'disc_number', type: Number }],
index: { field: 'disc_number', type: Number } index: { field: 'disc_number', type: Number }
}) })
@ -67,7 +67,7 @@ export default {
computed: { computed: {
heading() { heading() {
return { return {
count: this.$t('count.tracks', { count: this.album.track_count }), count: this.$t('data.tracks', { count: this.album.track_count }),
handler: this.openArtist, handler: this.openArtist,
subtitle: this.album.artist, subtitle: this.album.artist,
title: this.album.name, title: this.album.name,

View File

@ -43,7 +43,7 @@ export default {
}, },
beforeRouteEnter(to, from, next) { beforeRouteEnter(to, from, next) {
const spotifyApi = new SpotifyWebApi() const spotifyApi = new SpotifyWebApi()
webapi.spotify().then(({ data }) => { webapi.spotify().then((data) => {
spotifyApi.setAccessToken(data.webapi_token) spotifyApi.setAccessToken(data.webapi_token)
spotifyApi spotifyApi
.getAlbum(to.params.id, { .getAlbum(to.params.id, {
@ -68,7 +68,7 @@ export default {
computed: { computed: {
heading() { heading() {
return { return {
count: this.$t('count.tracks', { count: this.album.tracks.total }), count: this.$t('data.tracks', { count: this.album.tracks.total }),
handler: this.openArtist, handler: this.openArtist,
subtitle: this.album.artists[0].name, subtitle: this.album.artists[0].name,
title: this.album.name, title: this.album.name,

View File

@ -71,7 +71,7 @@ export default {
beforeRouteEnter(to, from, next) { beforeRouteEnter(to, from, next) {
webapi.library_albums('music').then((albums) => { webapi.library_albums('music').then((albums) => {
next((vm) => { next((vm) => {
vm.albumList = new GroupedList(albums.data) vm.albumList = new GroupedList(albums)
}) })
}) })
}, },
@ -143,7 +143,7 @@ export default {
}, },
heading() { heading() {
return { return {
subtitle: [{ count: this.albums.count, key: 'count.albums' }], subtitle: [{ count: this.albums.count, key: 'data.albums' }],
title: this.$t('page.albums.title') title: this.$t('page.albums.title')
} }
} }

View File

@ -77,8 +77,8 @@ export default {
webapi.library_artist_albums(to.params.id) webapi.library_artist_albums(to.params.id)
]).then(([artist, albums]) => { ]).then(([artist, albums]) => {
next((vm) => { next((vm) => {
vm.artist = artist.data vm.artist = artist
vm.albumList = new GroupedList(albums.data) vm.albumList = new GroupedList(albums)
}) })
}) })
}, },
@ -119,11 +119,11 @@ export default {
heading() { heading() {
return { return {
subtitle: [ subtitle: [
{ count: this.albums.count, key: 'count.albums' }, { count: this.albums.count, key: 'data.albums' },
{ {
count: this.trackCount, count: this.trackCount,
handler: this.openTracks, handler: this.openTracks,
key: 'count.tracks' key: 'data.tracks'
} }
], ],
title: this.artist.name title: this.artist.name

View File

@ -44,7 +44,7 @@ export default {
ModalDialogArtistSpotify ModalDialogArtistSpotify
}, },
beforeRouteEnter(to, from, next) { beforeRouteEnter(to, from, next) {
webapi.spotify().then(({ data }) => { webapi.spotify().then((data) => {
const spotifyApi = new SpotifyWebApi() const spotifyApi = new SpotifyWebApi()
spotifyApi.setAccessToken(data.webapi_token) spotifyApi.setAccessToken(data.webapi_token)
Promise.all([ Promise.all([
@ -80,7 +80,7 @@ export default {
computed: { computed: {
heading() { heading() {
return { return {
subtitle: [{ count: this.total, key: 'count.albums' }], subtitle: [{ count: this.total, key: 'data.albums' }],
title: this.artist.name title: this.artist.name
} }
}, },
@ -95,7 +95,7 @@ export default {
this.offset += data.limit this.offset += data.limit
}, },
load({ loaded }) { load({ loaded }) {
webapi.spotify().then(({ data }) => { webapi.spotify().then((data) => {
const spotifyApi = new SpotifyWebApi() const spotifyApi = new SpotifyWebApi()
spotifyApi.setAccessToken(data.webapi_token) spotifyApi.setAccessToken(data.webapi_token)
spotifyApi spotifyApi

View File

@ -80,8 +80,8 @@ export default {
webapi.library_artist_tracks(to.params.id) webapi.library_artist_tracks(to.params.id)
]).then(([artist, tracks]) => { ]).then(([artist, tracks]) => {
next((vm) => { next((vm) => {
vm.artist = artist.data vm.artist = artist
vm.trackList = new GroupedList(tracks.data.tracks) vm.trackList = new GroupedList(tracks)
}) })
}) })
}, },
@ -126,9 +126,9 @@ export default {
{ {
count: this.albumCount, count: this.albumCount,
handler: this.openArtist, handler: this.openArtist,
key: 'count.albums' key: 'data.albums'
}, },
{ count: this.tracks.count, key: 'count.tracks' } { count: this.tracks.count, key: 'data.tracks' }
], ],
title: this.artist.name title: this.artist.name
} }

View File

@ -71,7 +71,7 @@ export default {
beforeRouteEnter(to, from, next) { beforeRouteEnter(to, from, next) {
webapi.library_artists('music').then((artists) => { webapi.library_artists('music').then((artists) => {
next((vm) => { next((vm) => {
vm.artistList = new GroupedList(artists.data) vm.artistList = new GroupedList(artists)
}) })
}) })
}, },
@ -115,7 +115,7 @@ export default {
}, },
heading() { heading() {
return { return {
subtitle: [{ count: this.artists.count, key: 'count.artists' }], subtitle: [{ count: this.artists.count, key: 'data.artists' }],
title: this.$t('page.artists.title') title: this.$t('page.artists.title')
} }
} }

View File

@ -47,8 +47,8 @@ export default {
webapi.library_album_tracks(to.params.id) webapi.library_album_tracks(to.params.id)
]).then(([album, tracks]) => { ]).then(([album, tracks]) => {
next((vm) => { next((vm) => {
vm.album = album.data vm.album = album
vm.tracks = new GroupedList(tracks.data) vm.tracks = new GroupedList(tracks)
}) })
}) })
}, },
@ -62,7 +62,7 @@ export default {
computed: { computed: {
heading() { heading() {
return { return {
count: this.$t('count.tracks', { count: this.album.track_count }), count: this.$t('data.tracks', { count: this.album.track_count }),
handler: this.openArtist, handler: this.openArtist,
subtitle: this.album.artist, subtitle: this.album.artist,
title: this.album.name, title: this.album.name,

View File

@ -34,7 +34,7 @@ export default {
beforeRouteEnter(to, from, next) { beforeRouteEnter(to, from, next) {
webapi.library_albums('audiobook').then((albums) => { webapi.library_albums('audiobook').then((albums) => {
next((vm) => { next((vm) => {
vm.albums = new GroupedList(albums.data, { vm.albums = new GroupedList(albums, {
index: { field: 'name_sort', type: String } index: { field: 'name_sort', type: String }
}) })
}) })
@ -48,7 +48,7 @@ export default {
computed: { computed: {
heading() { heading() {
return { return {
subtitle: [{ count: this.albums.count, key: 'count.audiobooks' }], subtitle: [{ count: this.albums.count, key: 'data.audiobooks' }],
title: this.$t('page.audiobooks.albums.title') title: this.$t('page.audiobooks.albums.title')
} }
} }

View File

@ -46,8 +46,8 @@ export default {
webapi.library_artist_albums(to.params.id) webapi.library_artist_albums(to.params.id)
]).then(([artist, albums]) => { ]).then(([artist, albums]) => {
next((vm) => { next((vm) => {
vm.artist = artist.data vm.artist = artist
vm.albums = new GroupedList(albums.data) vm.albums = new GroupedList(albums)
}) })
}) })
}, },
@ -63,7 +63,7 @@ export default {
if (this.artist.name) { if (this.artist.name) {
return { return {
subtitle: [ subtitle: [
{ count: this.artist.album_count, key: 'count.audiobooks' } { count: this.artist.album_count, key: 'data.audiobooks' }
], ],
title: this.artist.name title: this.artist.name
} }

View File

@ -34,7 +34,7 @@ export default {
beforeRouteEnter(to, from, next) { beforeRouteEnter(to, from, next) {
webapi.library_artists('audiobook').then((artists) => { webapi.library_artists('audiobook').then((artists) => {
next((vm) => { next((vm) => {
vm.artists = new GroupedList(artists.data, { vm.artists = new GroupedList(artists, {
index: { field: 'name_sort', type: String } index: { field: 'name_sort', type: String }
}) })
}) })
@ -48,7 +48,7 @@ export default {
computed: { computed: {
heading() { heading() {
return { return {
subtitle: [{ count: this.artists.count, key: 'count.authors' }], subtitle: [{ count: this.artists.count, key: 'data.authors' }],
title: this.$t('page.audiobooks.artists.title') title: this.$t('page.audiobooks.artists.title')
} }
} }

View File

@ -32,9 +32,9 @@ export default {
TabsAudiobooks TabsAudiobooks
}, },
beforeRouteEnter(to, from, next) { beforeRouteEnter(to, from, next) {
webapi.library_genres('audiobook').then((response) => { webapi.library_genres('audiobook').then((genres) => {
next((vm) => { next((vm) => {
vm.genres = new GroupedList(response.data.genres, { vm.genres = new GroupedList(genres, {
index: { field: 'name_sort', type: String } index: { field: 'name_sort', type: String }
}) })
}) })
@ -48,7 +48,7 @@ export default {
computed: { computed: {
heading() { heading() {
return { return {
subtitle: [{ count: this.genres.total, key: 'count.genres' }], subtitle: [{ count: this.genres.total, key: 'data.genres' }],
title: this.$t('page.genres.title') title: this.$t('page.genres.title')
} }
} }

View File

@ -46,8 +46,8 @@ export default {
webapi.library_composer_albums(to.params.name) webapi.library_composer_albums(to.params.name)
]).then(([composer, albums]) => { ]).then(([composer, albums]) => {
next((vm) => { next((vm) => {
vm.composer = composer.data vm.composer = composer
vm.albums = new GroupedList(albums.data.albums) vm.albums = new GroupedList(albums)
}) })
}) })
}, },
@ -66,11 +66,11 @@ export default {
if (this.composer.name) { if (this.composer.name) {
return { return {
subtitle: [ subtitle: [
{ count: this.composer.album_count, key: 'count.albums' }, { count: this.composer.album_count, key: 'data.albums' },
{ {
count: this.composer.track_count, count: this.composer.track_count,
handler: this.openTracks, handler: this.openTracks,
key: 'count.tracks' key: 'data.tracks'
} }
], ],
title: this.composer.name title: this.composer.name

View File

@ -64,8 +64,8 @@ export default {
webapi.library_composer_tracks(to.params.name) webapi.library_composer_tracks(to.params.name)
]).then(([composer, tracks]) => { ]).then(([composer, tracks]) => {
next((vm) => { next((vm) => {
vm.composer = composer.data vm.composer = composer
vm.trackList = new GroupedList(tracks.data.tracks) vm.trackList = new GroupedList(tracks)
}) })
}) })
}, },
@ -107,9 +107,9 @@ export default {
{ {
count: this.composer.album_count, count: this.composer.album_count,
handler: this.openAlbums, handler: this.openAlbums,
key: 'count.albums' key: 'data.albums'
}, },
{ count: this.composer.track_count, key: 'count.tracks' } { count: this.composer.track_count, key: 'data.tracks' }
], ],
title: this.composer.name title: this.composer.name
} }

View File

@ -34,7 +34,7 @@ export default {
beforeRouteEnter(to, from, next) { beforeRouteEnter(to, from, next) {
webapi.library_composers('music').then((composers) => { webapi.library_composers('music').then((composers) => {
next((vm) => { next((vm) => {
vm.composers = new GroupedList(composers.data, { vm.composers = new GroupedList(composers, {
index: { field: 'name_sort', type: String } index: { field: 'name_sort', type: String }
}) })
}) })
@ -48,7 +48,7 @@ export default {
computed: { computed: {
heading() { heading() {
return { return {
subtitle: [{ count: this.composers.total, key: 'count.composers' }], subtitle: [{ count: this.composers.total, key: 'data.composers' }],
title: this.$t('page.composers.title') title: this.$t('page.composers.title')
} }
} }

View File

@ -93,17 +93,17 @@ export default {
methods: { methods: {
async fetchData(to) { async fetchData(to) {
if (to.query.directory) { if (to.query.directory) {
const response = await webapi.library_files(to.query.directory) const data = await webapi.library_files(to.query.directory)
if (response) { if (data) {
this.directories = response.data.directories.map((directory) => this.directories = data.directories.map((directory) =>
this.transform(directory.path) this.transform(directory.path)
) )
this.playlists = new GroupedList(response.data.playlists) this.playlists = new GroupedList(data.playlists)
this.tracks = new GroupedList(response.data.tracks) this.tracks = new GroupedList(data.tracks)
} }
} else { } else {
const config = await webapi.config() const config = await webapi.config()
this.directories = config.data.directories.map((path) => this.directories = config.directories.map((path) =>
this.transform(path) this.transform(path)
) )
this.playlists = new GroupedList() this.playlists = new GroupedList()

View File

@ -52,8 +52,8 @@ export default {
webapi.library_genre_albums(to.params.name, to.query.mediaKind) webapi.library_genre_albums(to.params.name, to.query.mediaKind)
]).then(([genre, albums]) => { ]).then(([genre, albums]) => {
next((vm) => { next((vm) => {
vm.genre = genre.data.genres.items.shift() vm.genre = genre.items.shift()
vm.albums = new GroupedList(albums.data.albums, { vm.albums = new GroupedList(albums, {
index: { field: 'name_sort', type: String } index: { field: 'name_sort', type: String }
}) })
}) })
@ -72,11 +72,11 @@ export default {
if (this.genre.name) { if (this.genre.name) {
return { return {
subtitle: [ subtitle: [
{ count: this.genre.album_count, key: 'count.albums' }, { count: this.genre.album_count, key: 'data.albums' },
{ {
count: this.genre.track_count, count: this.genre.track_count,
handler: this.openTracks, handler: this.openTracks,
key: 'count.tracks' key: 'data.tracks'
} }
], ],
title: this.genre.name title: this.genre.name

View File

@ -65,8 +65,8 @@ export default {
webapi.library_genre_tracks(to.params.name, to.query.mediaKind) webapi.library_genre_tracks(to.params.name, to.query.mediaKind)
]).then(([genre, tracks]) => { ]).then(([genre, tracks]) => {
next((vm) => { next((vm) => {
vm.genre = genre.data.genres.items.shift() vm.genre = genre.items.shift()
vm.trackList = new GroupedList(tracks.data.tracks) vm.trackList = new GroupedList(tracks)
}) })
}) })
}, },
@ -109,9 +109,9 @@ export default {
{ {
count: this.genre.album_count, count: this.genre.album_count,
handler: this.openGenre, handler: this.openGenre,
key: 'count.albums' key: 'data.albums'
}, },
{ count: this.genre.track_count, key: 'count.tracks' } { count: this.genre.track_count, key: 'data.tracks' }
], ],
title: this.genre.name title: this.genre.name
} }

View File

@ -34,7 +34,7 @@ export default {
beforeRouteEnter(to, from, next) { beforeRouteEnter(to, from, next) {
webapi.library_genres('music').then((genres) => { webapi.library_genres('music').then((genres) => {
next((vm) => { next((vm) => {
vm.genres = new GroupedList(genres.data.genres, { vm.genres = new GroupedList(genres, {
index: { field: 'name_sort', type: String } index: { field: 'name_sort', type: String }
}) })
}) })
@ -48,7 +48,7 @@ export default {
computed: { computed: {
heading() { heading() {
return { return {
subtitle: [{ count: this.genres.total, key: 'count.genres' }], subtitle: [{ count: this.genres.total, key: 'data.genres' }],
title: this.$t('page.genres.title') title: this.$t('page.genres.title')
} }
} }

View File

@ -70,10 +70,10 @@ export default {
limit: 3, limit: 3,
type: 'track' type: 'track'
}) })
]).then(([albums, tracks]) => { ]).then(([{ albums }, { tracks }]) => {
next((vm) => { next((vm) => {
vm.albums = new GroupedList(albums.data.albums) vm.albums = new GroupedList(albums)
vm.tracks = new GroupedList(tracks.data.tracks) vm.tracks = new GroupedList(tracks)
}) })
}) })
}, },

View File

@ -33,9 +33,9 @@ export default {
limit, limit,
type: 'album' type: 'album'
}) })
.then((response) => { .then((data) => {
next((vm) => { next((vm) => {
vm.albums = new GroupedList(response.data.albums, { vm.albums = new GroupedList(data.albums, {
criteria: [{ field: 'time_added', order: -1, type: Date }], criteria: [{ field: 'time_added', order: -1, type: Date }],
index: { field: 'time_added', type: Date } index: { field: 'time_added', type: Date }
}) })

View File

@ -31,9 +31,9 @@ export default {
limit: 50, limit: 50,
type: 'track' type: 'track'
}) })
.then((response) => { .then((data) => {
next((vm) => { next((vm) => {
vm.tracks = new GroupedList(response.data.tracks) vm.tracks = new GroupedList(data.tracks)
}) })
}) })
}, },

View File

@ -57,7 +57,7 @@ export default {
TabsMusic TabsMusic
}, },
beforeRouteEnter(to, from, next) { beforeRouteEnter(to, from, next) {
webapi.spotify().then(({ data }) => { webapi.spotify().then((data) => {
const spotifyApi = new SpotifyWebApi() const spotifyApi = new SpotifyWebApi()
spotifyApi.setAccessToken(data.webapi_token) spotifyApi.setAccessToken(data.webapi_token)
Promise.all([ Promise.all([

View File

@ -27,7 +27,7 @@ export default {
TabsMusic TabsMusic
}, },
beforeRouteEnter(to, from, next) { beforeRouteEnter(to, from, next) {
webapi.spotify().then(({ data }) => { webapi.spotify().then((data) => {
const spotifyApi = new SpotifyWebApi() const spotifyApi = new SpotifyWebApi()
spotifyApi.setAccessToken(data.webapi_token) spotifyApi.setAccessToken(data.webapi_token)
spotifyApi spotifyApi

View File

@ -27,7 +27,7 @@ export default {
TabsMusic TabsMusic
}, },
beforeRouteEnter(to, from, next) { beforeRouteEnter(to, from, next) {
webapi.spotify().then(({ data }) => { webapi.spotify().then((data) => {
const spotifyApi = new SpotifyWebApi() const spotifyApi = new SpotifyWebApi()
spotifyApi.setAccessToken(data.webapi_token) spotifyApi.setAccessToken(data.webapi_token)
spotifyApi spotifyApi

View File

@ -148,7 +148,7 @@ export default {
} }
}, },
created() { created() {
webapi.player_status().then(({ data }) => { webapi.player_status().then((data) => {
this.playerStore.$state = data this.playerStore.$state = data
if (this.playerStore.state === 'play') { if (this.playerStore.state === 'play') {
this.intervalId = window.setInterval(this.tick, INTERVAL) this.intervalId = window.setInterval(this.tick, INTERVAL)

View File

@ -42,7 +42,7 @@ export default {
computed: { computed: {
heading() { heading() {
return { return {
subtitle: [{ count: this.playlists.count, key: 'count.playlists' }], subtitle: [{ count: this.playlists.count, key: 'data.playlists' }],
title: this.$t('page.playlists.title', this.playlists.count, { title: this.$t('page.playlists.title', this.playlists.count, {
name: this.playlist.name name: this.playlist.name
}) })
@ -66,8 +66,8 @@ export default {
webapi.library_playlist(id), webapi.library_playlist(id),
webapi.library_playlist_folder(id) webapi.library_playlist_folder(id)
]) ])
this.playlist = playlist.data this.playlist = playlist
this.playlistList = new GroupedList(playlistFolder.data) this.playlistList = new GroupedList(playlistFolder)
} }
} }
} }

View File

@ -52,8 +52,8 @@ export default {
webapi.library_playlist_tracks(to.params.id) webapi.library_playlist_tracks(to.params.id)
]).then(([playlist, tracks]) => { ]).then(([playlist, tracks]) => {
next((vm) => { next((vm) => {
vm.playlist = playlist.data vm.playlist = playlist
vm.tracks = new GroupedList(tracks.data) vm.tracks = new GroupedList(tracks)
}) })
}) })
}, },
@ -67,7 +67,7 @@ export default {
computed: { computed: {
heading() { heading() {
return { return {
subtitle: [{ count: this.tracks.count, key: 'count.tracks' }], subtitle: [{ count: this.tracks.count, key: 'data.tracks' }],
title: this.playlist.name title: this.playlist.name
} }
}, },

View File

@ -63,8 +63,7 @@ export default {
market: useServicesStore().$state.spotify.webapi_country, market: useServicesStore().$state.spotify.webapi_country,
offset: 0 offset: 0
}) })
]).then((response) => { ]).then(([playlist, tracks]) => {
const [playlist, tracks] = response
next((vm) => { next((vm) => {
vm.playlist = playlist vm.playlist = playlist
vm.tracks = [] vm.tracks = []
@ -91,7 +90,7 @@ export default {
if (this.playlist.name) { if (this.playlist.name) {
return { return {
subtitle: [ subtitle: [
{ count: this.playlist.tracks.total, key: 'count.playlists' } { count: this.playlist.tracks.total, key: 'data.playlists' }
], ],
title: this.playlist.name title: this.playlist.name
} }

View File

@ -23,26 +23,8 @@
media-kind="podcast" media-kind="podcast"
@close="showDetailsModal = false" @close="showDetailsModal = false"
@play-count-changed="reloadTracks" @play-count-changed="reloadTracks"
@remove-podcast="openRemovePodcastDialog" @podcast-deleted="podcastDeleted"
/> />
<modal-dialog
:actions="actions"
:show="showRemovePodcastModal"
:title="$t('page.podcast.remove-podcast')"
@cancel="showRemovePodcastModal = false"
@remove="removePodcast"
>
<template #content>
<i18n-t keypath="page.podcast.remove-info" tag="p" scope="global">
<template #separator>
<br />
</template>
<template #name>
<b v-text="playlistToRemove.name" />
</template>
</i18n-t>
</template>
</modal-dialog>
</template> </template>
</content-with-hero> </content-with-hero>
</template> </template>
@ -53,7 +35,6 @@ import ControlImage from '@/components/ControlImage.vue'
import { GroupedList } from '@/lib/GroupedList' import { GroupedList } from '@/lib/GroupedList'
import HeadingHero from '@/components/HeadingHero.vue' import HeadingHero from '@/components/HeadingHero.vue'
import ListTracks from '@/components/ListTracks.vue' import ListTracks from '@/components/ListTracks.vue'
import ModalDialog from '@/components/ModalDialog.vue'
import ModalDialogAlbum from '@/components/ModalDialogAlbum.vue' import ModalDialogAlbum from '@/components/ModalDialogAlbum.vue'
import webapi from '@/webapi' import webapi from '@/webapi'
@ -64,47 +45,30 @@ export default {
ControlImage, ControlImage,
HeadingHero, HeadingHero,
ListTracks, ListTracks,
ModalDialog,
ModalDialogAlbum ModalDialogAlbum
}, },
beforeRouteEnter(to, from, next) { beforeRouteEnter(to, from, next) {
Promise.all([ Promise.all([
webapi.library_album(to.params.id), webapi.library_album(to.params.id),
webapi.library_podcast_episodes(to.params.id) webapi.library_podcast_episodes(to.params.id)
]).then(([album, episodes]) => { ]).then(([album, tracks]) => {
next((vm) => { next((vm) => {
vm.album = album.data vm.album = album
vm.tracks = new GroupedList(episodes.data.tracks) vm.tracks = new GroupedList(tracks)
}) })
}) })
}, },
data() { data() {
return { return {
album: {}, album: {},
playlistToRemove: {},
showDetailsModal: false, showDetailsModal: false,
showRemovePodcastModal: false,
tracks: new GroupedList() tracks: new GroupedList()
} }
}, },
computed: { computed: {
actions() {
return [
{
handler: 'cancel',
icon: 'cancel',
key: this.$t('page.podcast.cancel')
},
{
handler: 'remove',
icon: 'delete',
key: this.$t('page.podcast.remove')
}
]
},
heading() { heading() {
return { return {
count: this.$t('count.tracks', { count: this.album.track_count }), count: this.$t('data.tracks', { count: this.album.track_count }),
subtitle: '', subtitle: '',
title: this.album.name, title: this.album.name,
actions: [ actions: [
@ -115,33 +79,19 @@ export default {
} }
}, },
methods: { methods: {
openRemovePodcastDialog() {
webapi
.library_track_playlists(this.tracks.items[0].id)
.then(({ data }) => {
;[this.playlistToRemove] = data.items.filter(
(pl) => pl.type === 'rss'
)
this.showRemovePodcastModal = true
this.showDetailsModal = false
})
},
play() { play() {
webapi.player_play_uri(this.album.uri, false) webapi.player_play_uri(this.album.uri, false)
}, },
reloadTracks() { reloadTracks() {
webapi.library_podcast_episodes(this.album.id).then(({ data }) => { webapi.library_podcast_episodes(this.album.id).then((tracks) => {
this.tracks = new GroupedList(data.tracks) this.tracks = new GroupedList(tracks)
})
},
removePodcast() {
this.showRemovePodcastModal = false
webapi.library_playlist_delete(this.playlistToRemove.id).then(() => {
this.$router.replace({ name: 'podcasts' })
}) })
}, },
openDetails() { openDetails() {
this.showDetailsModal = true this.showDetailsModal = true
},
podcastDeleted() {
this.$router.push({ name: 'podcasts' })
} }
} }
} }

View File

@ -26,7 +26,7 @@
</template> </template>
<template #actions> <template #actions>
<control-button <control-button
v-if="rss.tracks > 0" v-if="libraryStore.rss"
:button="{ :button="{
handler: updateRss, handler: updateRss,
icon: 'refresh', icon: 'refresh',
@ -44,15 +44,15 @@
<template #content> <template #content>
<list-albums <list-albums
:items="albums" :items="albums"
@play-count-changed="reloadNewEpisodes()" @play-count-changed="reloadNewEpisodes"
@podcast-deleted="reloadPodcasts()" @podcast-deleted="reloadPodcasts"
/> />
</template> </template>
</content-with-heading> </content-with-heading>
<modal-dialog-add-rss <modal-dialog-add-rss
:show="showAddPodcastModal" :show="showAddPodcastModal"
@close="showAddPodcastModal = false" @close="showAddPodcastModal = false"
@podcast-added="reloadPodcasts()" @podcast-added="reloadPodcasts"
/> />
</template> </template>
@ -82,10 +82,10 @@ export default {
Promise.all([ Promise.all([
webapi.library_albums('podcast'), webapi.library_albums('podcast'),
webapi.library_podcasts_new_episodes() webapi.library_podcasts_new_episodes()
]).then(([albums, episodes]) => { ]).then(([albums, tracks]) => {
next((vm) => { next((vm) => {
vm.albums = new GroupedList(albums.data) vm.albums = new GroupedList(albums)
vm.tracks = new GroupedList(episodes.data.tracks) vm.tracks = new GroupedList(tracks)
}) })
}) })
}, },
@ -103,14 +103,11 @@ export default {
heading() { heading() {
if (this.albums.total) { if (this.albums.total) {
return { return {
subtitle: [{ count: this.albums.count, key: 'count.podcasts' }], subtitle: [{ count: this.albums.count, key: 'data.podcasts' }],
title: this.$t('page.podcasts.title') title: this.$t('page.podcasts.title')
} }
} }
return {} return {}
},
rss() {
return this.libraryStore.rss
} }
}, },
methods: { methods: {
@ -124,13 +121,13 @@ export default {
this.showAddPodcastModal = true this.showAddPodcastModal = true
}, },
reloadNewEpisodes() { reloadNewEpisodes() {
webapi.library_podcasts_new_episodes().then(({ data }) => { webapi.library_podcasts_new_episodes().then((tracks) => {
this.tracks = new GroupedList(data.tracks) this.tracks = new GroupedList(tracks)
}) })
}, },
reloadPodcasts() { reloadPodcasts() {
webapi.library_albums('podcast').then(({ data }) => { webapi.library_albums('podcast').then((albums) => {
this.albums = new GroupedList(data) this.albums = new GroupedList(albums)
this.reloadNewEpisodes() this.reloadNewEpisodes()
}) })
}, },

View File

@ -142,7 +142,7 @@ export default {
}, },
heading() { heading() {
return { return {
subtitle: [{ count: this.queueStore.count, key: 'count.tracks' }], subtitle: [{ count: this.queueStore.count, key: 'data.tracks' }],
title: this.$t('page.queue.title') title: this.$t('page.queue.title')
} }
}, },

View File

@ -20,9 +20,9 @@ export default {
name: 'PageRadioStreams', name: 'PageRadioStreams',
components: { ContentWithHeading, HeadingTitle, ListTracks }, components: { ContentWithHeading, HeadingTitle, ListTracks },
beforeRouteEnter(to, from, next) { beforeRouteEnter(to, from, next) {
webapi.library_radio_streams().then((radios) => { webapi.library_radio_streams().then((tracks) => {
next((vm) => { next((vm) => {
vm.tracks = new GroupedList(radios.data.tracks) vm.tracks = new GroupedList(tracks)
}) })
}) })
}, },
@ -34,7 +34,7 @@ export default {
computed: { computed: {
heading() { heading() {
return { return {
subtitle: [{ count: this.tracks.total, key: 'count.stations' }], subtitle: [{ count: this.tracks.total, key: 'data.stations' }],
title: this.$t('page.radio.title') title: this.$t('page.radio.title')
} }
} }

View File

@ -190,7 +190,7 @@ export default {
} else { } else {
parameters.expression = `(album includes "${this.searchStore.query}" or artist includes "${this.searchStore.query}") and media_kind is ${kind}` parameters.expression = `(album includes "${this.searchStore.query}" or artist includes "${this.searchStore.query}") and media_kind is ${kind}`
} }
webapi.search(parameters).then(({ data }) => { webapi.search(parameters).then((data) => {
this.results.set(type, new GroupedList(data[`${parameters.type}s`])) this.results.set(type, new GroupedList(data[`${parameters.type}s`]))
}) })
}, },

View File

@ -158,7 +158,7 @@ export default {
} }
}, },
searchItems() { searchItems() {
return webapi.spotify().then(({ data }) => { return webapi.spotify().then((data) => {
this.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)

View File

@ -140,16 +140,16 @@ export default {
}, },
methods: { methods: {
loginLastfm() { loginLastfm() {
webapi.lastfm_login(this.lastfm_login).then((response) => { webapi.lastfm_login(this.lastfm_login).then((data) => {
this.lastfm_login.user = '' this.lastfm_login.user = ''
this.lastfm_login.password = '' this.lastfm_login.password = ''
this.lastfm_login.errors.user = '' this.lastfm_login.errors.user = ''
this.lastfm_login.errors.password = '' this.lastfm_login.errors.password = ''
this.lastfm_login.errors.error = '' this.lastfm_login.errors.error = ''
if (!response.data.success) { if (!data.success) {
this.lastfm_login.errors.user = response.data.errors.user this.lastfm_login.errors.user = data.errors.user
this.lastfm_login.errors.password = response.data.errors.password this.lastfm_login.errors.password = data.errors.password
this.lastfm_login.errors.error = response.data.errors.error this.lastfm_login.errors.error = data.errors.error
} }
}) })
}, },

View File

@ -6,7 +6,7 @@ import { useQueueStore } from '@/stores/queue'
const { t } = i18n.global const { t } = i18n.global
axios.interceptors.response.use( axios.interceptors.response.use(
(response) => response, (response) => response.data,
(error) => { (error) => {
if (error.request.status && error.request.responseURL) { if (error.request.status && error.request.responseURL) {
useNotificationsStore().add({ useNotificationsStore().add({
@ -71,12 +71,13 @@ export default {
return axios.get(`./api/library/artists/${artistId}/albums`) return axios.get(`./api/library/artists/${artistId}/albums`)
}, },
library_artist_tracks(artist) { async library_artist_tracks(artist) {
const params = { const params = {
expression: `songartistid is "${artist}"`, expression: `songartistid is "${artist}"`,
type: 'tracks' type: 'tracks'
} }
return axios.get('./api/search', { params }) const data = await axios.get('./api/search', { params })
return data.tracks
}, },
library_artists(media_kind) { library_artists(media_kind) {
@ -87,20 +88,22 @@ export default {
return axios.get(`./api/library/composers/${encodeURIComponent(composer)}`) return axios.get(`./api/library/composers/${encodeURIComponent(composer)}`)
}, },
library_composer_albums(composer) { async library_composer_albums(composer) {
const params = { const params = {
expression: `composer is "${composer}" and media_kind is music`, expression: `composer is "${composer}" and media_kind is music`,
type: 'albums' type: 'albums'
} }
return axios.get('./api/search', { params }) const data = await axios.get('./api/search', { params })
return data.albums
}, },
library_composer_tracks(composer) { async library_composer_tracks(composer) {
const params = { const params = {
expression: `composer is "${composer}" and media_kind is music`, expression: `composer is "${composer}" and media_kind is music`,
type: 'tracks' type: 'tracks'
} }
return axios.get('./api/search', { params }) const data = await axios.get('./api/search', { params })
return data.tracks
}, },
library_composers(media_kind) { library_composers(media_kind) {
@ -115,36 +118,40 @@ export default {
return axios.get('./api/library/files', { params: { directory } }) return axios.get('./api/library/files', { params: { directory } })
}, },
library_genre(genre, media_kind) { async library_genre(genre, media_kind) {
const params = { const params = {
expression: `genre is "${genre}" and media_kind is ${media_kind}`, expression: `genre is "${genre}" and media_kind is ${media_kind}`,
type: 'genres' type: 'genres'
} }
return axios.get('./api/search', { params }) const data = await axios.get('./api/search', { params })
return data.genres
}, },
library_genre_albums(genre, media_kind) { async library_genre_albums(genre, media_kind) {
const params = { const params = {
expression: `genre is "${genre}" and media_kind is ${media_kind}`, expression: `genre is "${genre}" and media_kind is ${media_kind}`,
type: 'albums' type: 'albums'
} }
return axios.get('./api/search', { params }) const data = await axios.get('./api/search', { params })
return data.albums
}, },
library_genre_tracks(genre, media_kind) { async library_genre_tracks(genre, media_kind) {
const params = { const params = {
expression: `genre is "${genre}" and media_kind is ${media_kind}`, expression: `genre is "${genre}" and media_kind is ${media_kind}`,
type: 'tracks' type: 'tracks'
} }
return axios.get('./api/search', { params }) const data = await axios.get('./api/search', { params })
return data.tracks
}, },
library_genres(media_kind) { async library_genres(media_kind) {
const params = { const params = {
expression: `media_kind is ${media_kind}`, expression: `media_kind is ${media_kind}`,
type: 'genres' type: 'genres'
} }
return axios.get('./api/search', { params }) const data = await axios.get('./api/search', { params })
return data.genres
}, },
library_playlist(playlistId) { library_playlist(playlistId) {
@ -152,7 +159,7 @@ export default {
}, },
library_playlist_delete(playlistId) { library_playlist_delete(playlistId) {
return axios.delete(`./api/library/playlists/${playlistId}`, null) return axios.delete(`./api/library/playlists/${playlistId}`)
}, },
library_playlist_folder(playlistId = 0) { library_playlist_folder(playlistId = 0) {
@ -163,30 +170,33 @@ export default {
return axios.get(`./api/library/playlists/${playlistId}/tracks`) return axios.get(`./api/library/playlists/${playlistId}/tracks`)
}, },
library_podcast_episodes(albumId) { async library_podcast_episodes(albumId) {
const params = { const params = {
expression: `media_kind is podcast and songalbumid is "${albumId}" ORDER BY date_released DESC`, expression: `media_kind is podcast and songalbumid is "${albumId}" ORDER BY date_released DESC`,
type: 'tracks' type: 'tracks'
} }
return axios.get('./api/search', { params }) const data = await axios.get('./api/search', { params })
return data.tracks
}, },
library_podcasts_new_episodes() { async library_podcasts_new_episodes() {
const params = { const params = {
expression: expression:
'media_kind is podcast and play_count = 0 ORDER BY time_added DESC', 'media_kind is podcast and play_count = 0 ORDER BY time_added DESC',
type: 'tracks' type: 'tracks'
} }
return axios.get('./api/search', { params }) const data = await axios.get('./api/search', { params })
return data.tracks
}, },
library_radio_streams() { async library_radio_streams() {
const params = { const params = {
expression: 'data_kind is url and song_length = 0', expression: 'data_kind is url and song_length = 0',
media_kind: 'music', media_kind: 'music',
type: 'tracks' type: 'tracks'
} }
return axios.get('./api/search', { params }) const data = await axios.get('./api/search', { params })
return data.tracks
}, },
library_rescan(scan_kind) { library_rescan(scan_kind) {
@ -316,13 +326,13 @@ export default {
}, },
async queue_add(uri) { async queue_add(uri) {
const response = await axios.post(`./api/queue/items/add?uris=${uri}`) const data = await axios.post(`./api/queue/items/add?uris=${uri}`)
useNotificationsStore().add({ useNotificationsStore().add({
text: t('server.appended-tracks', { count: response.data.count }), text: t('server.appended-tracks', { count: data.count }),
timeout: 2000, timeout: 2000,
type: 'info' type: 'info'
}) })
return await Promise.resolve(response) return await Promise.resolve(data)
}, },
async queue_add_next(uri) { async queue_add_next(uri) {
@ -331,15 +341,15 @@ export default {
if (current?.id) { if (current?.id) {
position = current.position + 1 position = current.position + 1
} }
const response = await axios.post( const data = await axios.post(
`./api/queue/items/add?uris=${uri}&position=${position}` `./api/queue/items/add?uris=${uri}&position=${position}`
) )
useNotificationsStore().add({ useNotificationsStore().add({
text: t('server.appended-tracks', { count: response.data.count }), text: t('server.appended-tracks', { count: data.count }),
timeout: 2000, timeout: 2000,
type: 'info' type: 'info'
}) })
return await Promise.resolve(response) return await Promise.resolve(data)
}, },
queue_clear() { queue_clear() {
@ -347,15 +357,15 @@ export default {
}, },
async queue_expression_add(expression) { async queue_expression_add(expression) {
const response = await axios.post('./api/queue/items/add', null, { const data = await axios.post('./api/queue/items/add', null, {
params: { expression } params: { expression }
}) })
useNotificationsStore().add({ useNotificationsStore().add({
text: t('server.appended-tracks', { count: response.data.count }), text: t('server.appended-tracks', { count: data.count }),
timeout: 2000, timeout: 2000,
type: 'info' type: 'info'
}) })
return await Promise.resolve(response) return await Promise.resolve(data)
}, },
async queue_expression_add_next(expression) { async queue_expression_add_next(expression) {
@ -366,13 +376,13 @@ export default {
if (current?.id) { if (current?.id) {
params.position = current.position + 1 params.position = current.position + 1
} }
const response = await axios.post('./api/queue/items/add', null, { params }) const data = await axios.post('./api/queue/items/add', null, { params })
useNotificationsStore().add({ useNotificationsStore().add({
text: t('server.appended-tracks', { count: response.data.count }), text: t('server.appended-tracks', { count: data.count }),
timeout: 2000, timeout: 2000,
type: 'info' type: 'info'
}) })
return await Promise.resolve(response) return await Promise.resolve(data)
}, },
queue_move(itemId, position) { queue_move(itemId, position) {