mirror of
https://github.com/owntone/owntone-server.git
synced 2025-07-20 14:01:17 -04:00
[web] Fix a bug in the Spotify search
This commit is contained in:
parent
eb33a25ce7
commit
4adb623c3f
@ -34,7 +34,6 @@ export default {
|
|||||||
props: {
|
props: {
|
||||||
items: { required: true, type: Object },
|
items: { required: true, type: Object },
|
||||||
load: { default: null, type: Function },
|
load: { default: null, type: Function },
|
||||||
loaded: { default: true, type: Boolean },
|
|
||||||
mediaKind: { default: '', type: String }
|
mediaKind: { default: '', type: String }
|
||||||
},
|
},
|
||||||
emits: ['play-count-changed', 'podcast-deleted'],
|
emits: ['play-count-changed', 'podcast-deleted'],
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
@open="open(item)"
|
@open="open(item)"
|
||||||
@open-details="openDetails(item)"
|
@open-details="openDetails(item)"
|
||||||
/>
|
/>
|
||||||
<loader-list-item :load="load" :loaded="loaded" />
|
<loader-list-item :load="load" />
|
||||||
<modal-dialog-album-spotify
|
<modal-dialog-album-spotify
|
||||||
:item="selectedItem"
|
:item="selectedItem"
|
||||||
:show="showDetailsModal"
|
:show="showDetailsModal"
|
||||||
@ -32,8 +32,7 @@ export default {
|
|||||||
components: { ListItem, LoaderListItem, ModalDialogAlbumSpotify },
|
components: { ListItem, LoaderListItem, ModalDialogAlbumSpotify },
|
||||||
props: {
|
props: {
|
||||||
items: { required: true, type: Object },
|
items: { required: true, type: Object },
|
||||||
load: { default: null, type: Function },
|
load: { default: null, type: Function }
|
||||||
loaded: { default: true, type: Boolean }
|
|
||||||
},
|
},
|
||||||
setup() {
|
setup() {
|
||||||
return { settingsStore: useSettingsStore() }
|
return { settingsStore: useSettingsStore() }
|
||||||
|
@ -24,8 +24,7 @@ export default {
|
|||||||
components: { ListItem, ModalDialogArtist },
|
components: { ListItem, ModalDialogArtist },
|
||||||
props: {
|
props: {
|
||||||
items: { required: true, type: Object },
|
items: { required: true, type: Object },
|
||||||
load: { default: null, type: Function },
|
load: { default: null, type: Function }
|
||||||
loaded: { default: true, type: Boolean }
|
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return { selectedItem: {}, showDetailsModal: false }
|
return { selectedItem: {}, showDetailsModal: false }
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
@open="open(item)"
|
@open="open(item)"
|
||||||
@open-details="openDetails(item)"
|
@open-details="openDetails(item)"
|
||||||
/>
|
/>
|
||||||
<loader-list-item :load="load" :loaded="loaded" />
|
<loader-list-item :load="load" />
|
||||||
<modal-dialog-artist-spotify
|
<modal-dialog-artist-spotify
|
||||||
:item="selectedItem"
|
:item="selectedItem"
|
||||||
:show="showDetailsModal"
|
:show="showDetailsModal"
|
||||||
@ -26,8 +26,7 @@ export default {
|
|||||||
components: { ListItem, LoaderListItem, ModalDialogArtistSpotify },
|
components: { ListItem, LoaderListItem, ModalDialogArtistSpotify },
|
||||||
props: {
|
props: {
|
||||||
items: { required: true, type: Object },
|
items: { required: true, type: Object },
|
||||||
load: { default: null, type: Function },
|
load: { default: null, type: Function }
|
||||||
loaded: { default: true, type: Boolean }
|
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return { selectedItem: {}, showDetailsModal: false }
|
return { selectedItem: {}, showDetailsModal: false }
|
||||||
|
@ -24,8 +24,7 @@ export default {
|
|||||||
components: { ListItem, ModalDialogComposer },
|
components: { ListItem, ModalDialogComposer },
|
||||||
props: {
|
props: {
|
||||||
items: { required: true, type: Object },
|
items: { required: true, type: Object },
|
||||||
load: { default: null, type: Function },
|
load: { default: null, type: Function }
|
||||||
loaded: { default: true, type: Boolean }
|
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return { selectedItem: {}, showDetailsModal: false }
|
return { selectedItem: {}, showDetailsModal: false }
|
||||||
|
@ -25,8 +25,7 @@ export default {
|
|||||||
components: { ListItem, ModalDialogPlaylist },
|
components: { ListItem, ModalDialogPlaylist },
|
||||||
props: {
|
props: {
|
||||||
items: { required: true, type: Object },
|
items: { required: true, type: Object },
|
||||||
load: { default: null, type: Function },
|
load: { default: null, type: Function }
|
||||||
loaded: { default: true, type: Boolean }
|
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return { selectedItem: {}, showDetailsModal: false }
|
return { selectedItem: {}, showDetailsModal: false }
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
@open="open(item)"
|
@open="open(item)"
|
||||||
@open-details="openDetails(item)"
|
@open-details="openDetails(item)"
|
||||||
/>
|
/>
|
||||||
<loader-list-item :load="load" :loaded="loaded" />
|
<loader-list-item :load="load" />
|
||||||
<modal-dialog-playlist-spotify
|
<modal-dialog-playlist-spotify
|
||||||
:item="selectedItem"
|
:item="selectedItem"
|
||||||
:show="showDetailsModal"
|
:show="showDetailsModal"
|
||||||
@ -26,8 +26,7 @@ export default {
|
|||||||
components: { ListItem, LoaderListItem, ModalDialogPlaylistSpotify },
|
components: { ListItem, LoaderListItem, ModalDialogPlaylistSpotify },
|
||||||
props: {
|
props: {
|
||||||
items: { required: true, type: Object },
|
items: { required: true, type: Object },
|
||||||
load: { default: null, type: Function },
|
load: { default: null, type: Function }
|
||||||
loaded: { default: true, type: Boolean }
|
|
||||||
},
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
|
@ -32,7 +32,6 @@ export default {
|
|||||||
icon: { default: null, type: String },
|
icon: { default: null, type: String },
|
||||||
items: { default: null, type: Object },
|
items: { default: null, type: Object },
|
||||||
load: { default: null, type: Function },
|
load: { default: null, type: Function },
|
||||||
loaded: { default: true, type: Boolean },
|
|
||||||
showProgress: { default: false, type: Boolean },
|
showProgress: { default: false, type: Boolean },
|
||||||
uris: { default: '', type: String }
|
uris: { default: '', type: String }
|
||||||
},
|
},
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
/>)
|
/>)
|
||||||
</template>
|
</template>
|
||||||
</list-item>
|
</list-item>
|
||||||
<loader-list-item :load="load" :loaded="loaded" />
|
<loader-list-item :load="load" />
|
||||||
<modal-dialog-track-spotify
|
<modal-dialog-track-spotify
|
||||||
:item="selectedItem"
|
:item="selectedItem"
|
||||||
:show="showDetailsModal"
|
:show="showDetailsModal"
|
||||||
@ -39,8 +39,7 @@ export default {
|
|||||||
props: {
|
props: {
|
||||||
contextUri: { default: '', type: String },
|
contextUri: { default: '', type: String },
|
||||||
items: { required: true, type: Object },
|
items: { required: true, type: Object },
|
||||||
load: { default: null, type: Function },
|
load: { default: null, type: Function }
|
||||||
loaded: { default: true, type: Boolean }
|
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return { selectedItem: {}, showDetailsModal: false }
|
return { selectedItem: {}, showDetailsModal: false }
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<vue-eternal-loading v-if="load && !loaded" :load="load">
|
<vue-eternal-loading v-if="load" :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">
|
||||||
@ -23,8 +23,7 @@ export default {
|
|||||||
name: 'LoaderListItem',
|
name: 'LoaderListItem',
|
||||||
components: { VueEternalLoading },
|
components: { VueEternalLoading },
|
||||||
props: {
|
props: {
|
||||||
load: { default: null, type: Function },
|
load: { default: null, type: Function }
|
||||||
loaded: { default: true, type: Boolean }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<template #content>
|
<template #content>
|
||||||
<list-albums-spotify :items="albums" :load="load" :loaded="loaded" />
|
<list-albums-spotify :items="albums" :load="load" />
|
||||||
</template>
|
</template>
|
||||||
</content-with-heading>
|
</content-with-heading>
|
||||||
<modal-dialog-artist-spotify
|
<modal-dialog-artist-spotify
|
||||||
@ -84,9 +84,6 @@ export default {
|
|||||||
subtitle: [{ count: this.total, key: 'data.albums' }],
|
subtitle: [{ count: this.total, key: 'data.albums' }],
|
||||||
title: this.artist.name
|
title: this.artist.name
|
||||||
}
|
}
|
||||||
},
|
|
||||||
loaded() {
|
|
||||||
return !(this.offset < this.total)
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
@ -21,7 +21,6 @@
|
|||||||
:context-uri="playlist.uri"
|
:context-uri="playlist.uri"
|
||||||
:items="tracks"
|
:items="tracks"
|
||||||
:load="load"
|
:load="load"
|
||||||
:loaded="loaded"
|
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</content-with-heading>
|
</content-with-heading>
|
||||||
@ -96,9 +95,6 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {}
|
return {}
|
||||||
},
|
|
||||||
loaded() {
|
|
||||||
return !(this.offset < this.total)
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
@ -44,8 +44,8 @@ import ListTracks from '@/components/ListTracks.vue'
|
|||||||
import library from '@/api/library'
|
import library from '@/api/library'
|
||||||
import { useSearchStore } from '@/stores/search'
|
import { useSearchStore } from '@/stores/search'
|
||||||
|
|
||||||
const PAGE_SIZE = 3,
|
const PAGE_SIZE = 3
|
||||||
SEARCH_TYPES = [
|
const SEARCH_TYPES = [
|
||||||
'track',
|
'track',
|
||||||
'artist',
|
'artist',
|
||||||
'album',
|
'album',
|
||||||
@ -53,7 +53,7 @@ const PAGE_SIZE = 3,
|
|||||||
'playlist',
|
'playlist',
|
||||||
'audiobook',
|
'audiobook',
|
||||||
'podcast'
|
'podcast'
|
||||||
]
|
]
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'PageSearchLibrary',
|
name: 'PageSearchLibrary',
|
||||||
@ -72,7 +72,7 @@ export default {
|
|||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
limit: {},
|
limit: PAGE_SIZE,
|
||||||
results: new Map(),
|
results: new Map(),
|
||||||
types: SEARCH_TYPES
|
types: SEARCH_TYPES
|
||||||
}
|
}
|
||||||
@ -86,23 +86,17 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.searchStore.source = this.$route.name
|
|
||||||
this.limit = PAGE_SIZE
|
|
||||||
this.search()
|
this.search()
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
expand(type) {
|
expand(type) {
|
||||||
this.types = [type]
|
this.search([type], -1)
|
||||||
this.limit = -1
|
|
||||||
this.search()
|
|
||||||
},
|
},
|
||||||
getItems(items) {
|
getItems(items) {
|
||||||
return items
|
return items
|
||||||
},
|
},
|
||||||
openSearch(query) {
|
openSearch(query) {
|
||||||
this.searchStore.query = query
|
this.searchStore.query = query
|
||||||
this.types = SEARCH_TYPES
|
|
||||||
this.limit = PAGE_SIZE
|
|
||||||
this.search()
|
this.search()
|
||||||
},
|
},
|
||||||
reset() {
|
reset() {
|
||||||
@ -111,12 +105,10 @@ export default {
|
|||||||
this.results.set(type, new GroupedList())
|
this.results.set(type, new GroupedList())
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
search(event) {
|
search(types = SEARCH_TYPES, limit = PAGE_SIZE) {
|
||||||
if (this.searchStore.query) {
|
if (this.searchStore.query) {
|
||||||
if (event) {
|
this.types = types
|
||||||
this.types = SEARCH_TYPES
|
this.limit = limit
|
||||||
this.limit = PAGE_SIZE
|
|
||||||
}
|
|
||||||
this.searchStore.query = this.searchStore.query.trim()
|
this.searchStore.query = this.searchStore.query.trim()
|
||||||
this.reset()
|
this.reset()
|
||||||
this.types.forEach((type) => {
|
this.types.forEach((type) => {
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
:expanded="expanded"
|
:expanded="expanded"
|
||||||
:get-items="getItems"
|
:get-items="getItems"
|
||||||
:history="history"
|
:history="history"
|
||||||
|
:load="(expanded && searchNext) || null"
|
||||||
:results="results"
|
:results="results"
|
||||||
@search="search"
|
@search="search"
|
||||||
@search-library="searchLibrary"
|
@search-library="searchLibrary"
|
||||||
@ -23,9 +24,9 @@ import SpotifyWebApi from 'spotify-web-api-js'
|
|||||||
import services from '@/api/services'
|
import services from '@/api/services'
|
||||||
import { useSearchStore } from '@/stores/search'
|
import { useSearchStore } from '@/stores/search'
|
||||||
|
|
||||||
const PAGE_SIZE = 3,
|
const PAGE_SIZE = 3
|
||||||
PAGE_SIZE_EXPANDED = 50,
|
const PAGE_SIZE_EXPANDED = 50
|
||||||
SEARCH_TYPES = ['track', 'artist', 'album', 'playlist']
|
const SEARCH_TYPES = ['track', 'artist', 'album', 'playlist']
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'PageSearchSpotify',
|
name: 'PageSearchSpotify',
|
||||||
@ -43,8 +44,8 @@ export default {
|
|||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
results: new Map(),
|
|
||||||
parameters: {},
|
parameters: {},
|
||||||
|
results: new Map(),
|
||||||
types: SEARCH_TYPES
|
types: SEARCH_TYPES
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -59,25 +60,17 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.searchStore.source = this.$route.name
|
|
||||||
this.parameters.limit = PAGE_SIZE
|
|
||||||
this.search()
|
this.search()
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
expand(type) {
|
expand(type) {
|
||||||
this.types = [type]
|
this.search([type], PAGE_SIZE_EXPANDED)
|
||||||
this.parameters.limit = PAGE_SIZE_EXPANDED
|
|
||||||
this.parameters.offset = 0
|
|
||||||
this.search()
|
|
||||||
},
|
},
|
||||||
getItems(items) {
|
getItems(items) {
|
||||||
return items.items
|
return items.items
|
||||||
},
|
},
|
||||||
openSearch(query) {
|
openSearch(query) {
|
||||||
this.searchStore.query = query
|
this.searchStore.query = query
|
||||||
this.types = SEARCH_TYPES
|
|
||||||
this.parameters.limit = PAGE_SIZE
|
|
||||||
this.parameters.offset = 0
|
|
||||||
this.search()
|
this.search()
|
||||||
},
|
},
|
||||||
reset() {
|
reset() {
|
||||||
@ -86,12 +79,11 @@ export default {
|
|||||||
this.results.set(type, { items: [], total: 0 })
|
this.results.set(type, { items: [], total: 0 })
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
search(event) {
|
search(types = SEARCH_TYPES, limit = PAGE_SIZE, offset = 0) {
|
||||||
if (this.searchStore.query) {
|
if (this.searchStore.query) {
|
||||||
if (event) {
|
this.types = types
|
||||||
this.types = SEARCH_TYPES
|
this.parameters.limit = limit
|
||||||
this.parameters.limit = PAGE_SIZE
|
this.parameters.offset = offset
|
||||||
}
|
|
||||||
this.searchStore.query = this.searchStore.query.trim()
|
this.searchStore.query = this.searchStore.query.trim()
|
||||||
this.reset()
|
this.reset()
|
||||||
this.searchItems().then((data) => {
|
this.searchItems().then((data) => {
|
||||||
@ -123,9 +115,8 @@ export default {
|
|||||||
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
|
this.parameters.offset += next.items.length
|
||||||
this.parameters.offset = (this.parameters.offset || 0) + next.limit
|
loaded(Number(next.next && next.limit), PAGE_SIZE_EXPANDED)
|
||||||
loaded(next.items.length, PAGE_SIZE_EXPANDED)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,16 +43,11 @@
|
|||||||
<pane-title :content="{ title: $t(`page.search.${type}s`) }" />
|
<pane-title :content="{ title: $t(`page.search.${type}s`) }" />
|
||||||
</template>
|
</template>
|
||||||
<template #content>
|
<template #content>
|
||||||
<component
|
<component :is="components[type]" :items="getItems(items)" :load="load" />
|
||||||
:is="components[type]"
|
|
||||||
:items="getItems(items)"
|
|
||||||
:load="load"
|
|
||||||
:loaded="!expanded"
|
|
||||||
/>
|
|
||||||
</template>
|
</template>
|
||||||
<template v-if="!expanded" #footer>
|
<template v-if="!expanded" #footer>
|
||||||
<control-button
|
<control-button
|
||||||
v-if="showAllButton(items)"
|
v-if="items.total"
|
||||||
:button="{
|
:button="{
|
||||||
handler: () => $emit('expand', type),
|
handler: () => $emit('expand', type),
|
||||||
title: $t(
|
title: $t(
|
||||||
@ -62,7 +57,7 @@
|
|||||||
)
|
)
|
||||||
}"
|
}"
|
||||||
/>
|
/>
|
||||||
<div v-if="!items.total" class="has-text-centered-mobile">
|
<div v-else class="has-text-centered-mobile">
|
||||||
<i v-text="$t('page.search.no-results')" />
|
<i v-text="$t('page.search.no-results')" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -98,11 +93,6 @@ export default {
|
|||||||
return {
|
return {
|
||||||
searchStore: useSearchStore()
|
searchStore: useSearchStore()
|
||||||
}
|
}
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
showAllButton(items) {
|
|
||||||
return items.total > items.items.length
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user