Merge pull request #1441 from chme/web/next

[web] Update web interface
This commit is contained in:
Christian Meffert 2022-04-16 07:11:04 +02:00 committed by GitHub
commit b3a661cae8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 738 additions and 645 deletions

View File

@ -25,7 +25,6 @@ htdocsassetsdir = $(datadir)/owntone/htdocs/assets
dist_htdocsassets_DATA = \
assets/index.css \
assets/index.js \
assets/vendor.js \
assets/materialdesignicons-webfont.svg \
assets/materialdesignicons-webfont.ttf \
assets/materialdesignicons-webfont.woff2 \

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -17,7 +17,6 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>OwnTone</title>
<script type="module" crossorigin src="/assets/index.js"></script>
<link rel="modulepreload" href="/assets/vendor.js">
<link rel="stylesheet" href="/assets/index.css">
</head>
<body>

File diff suppressed because it is too large Load Diff

View File

@ -12,17 +12,16 @@
"dependencies": {
"@aacassandra/vue3-progressbar": "^1.0.3",
"@ts-pro/vue-eternal-loading": "^1.2.0",
"@vueform/slider": "^2.0.9",
"@vueform/slider": "github:chme/slider#faff83ed8a77f2cdbcb7252505ef734301efd139",
"axios": "^0.26.1",
"bulma": "^0.9.3",
"bulma-switch": "^2.0.4",
"luxon": "^2.3.1",
"mdi": "^2.2.43",
"moment": "^2.29.1",
"moment-duration-format": "^2.3.2",
"reconnectingwebsocket": "^1.0.0",
"spotify-web-api-js": "^1.5.2",
"string-to-color": "^2.2.2",
"vue": "^3.2.31",
"vue": "^3.2.33",
"vue-router": "^4.0.14",
"vue-scrollto": "^2.20.0",
"vue3-click-away": "^1.2.4",
@ -31,12 +30,12 @@
"vuex": "^4.0.2"
},
"devDependencies": {
"@vitejs/plugin-vue": "^2.2.4",
"eslint": "^8.11.0",
"@vitejs/plugin-vue": "^2.3.1",
"eslint": "^8.13.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-vue": "^8.5.0",
"prettier": "2.6.0",
"sass": "^1.49.9",
"vite": "^2.8.6"
"eslint-plugin-vue": "^8.6.0",
"prettier": "2.6.2",
"sass": "^1.50.0",
"vite": "^2.9.5"
}
}

View File

@ -33,7 +33,6 @@ import ModalDialogUpdate from '@/components/ModalDialogUpdate.vue'
import webapi from '@/webapi'
import * as types from '@/store/mutation_types'
import ReconnectingWebSocket from 'reconnectingwebsocket'
import moment from 'moment'
export default {
name: 'App',
@ -90,7 +89,6 @@ export default {
},
created: function () {
moment.locale(navigator.language)
this.connect()
// Start the progress bar on app start

View File

@ -9,7 +9,7 @@
</div>
<div v-else-if="album.isItem" class="media" @click="open_album(album.item)">
<div v-if="is_visible_artwork" class="media-left fd-has-action">
<p class="image is-64x64 fd-has-shadow fd-has-action">
<div class="image is-64x64 fd-has-shadow fd-has-action">
<figure>
<img
v-lazy="{
@ -20,7 +20,7 @@
:artist="album.item.artist"
/>
</figure>
</p>
</div>
</div>
<div class="media-content fd-has-action is-clipped">
<div style="margin-top: 0.7rem">
@ -34,7 +34,7 @@
v-if="album.item.date_released && album.item.media_kind === 'music'"
class="subtitle is-7 has-text-grey has-text-weight-normal"
>
{{ $filters.time(album.item.date_released, 'L') }}
{{ $filters.date(album.item.date_released) }}
</h2>
</div>
</div>

View File

@ -35,7 +35,7 @@
<p v-if="album.date_released">
<span class="heading">Release date</span>
<span class="title is-6">{{
$filters.time(album.date_released, 'L')
$filters.date(album.date_released)
}}</span>
</p>
<p v-else-if="album.year > 0">
@ -49,7 +49,7 @@
<p>
<span class="heading">Length</span>
<span class="title is-6">{{
$filters.duration(album.length_ms)
$filters.durationInHours(album.length_ms)
}}</span>
</p>
<p>
@ -61,7 +61,7 @@
<p>
<span class="heading">Added at</span>
<span class="title is-6">{{
$filters.time(album.time_added, 'L LT')
$filters.datetime(album.time_added)
}}</span>
</p>
</div>

View File

@ -27,7 +27,7 @@
<p>
<span class="heading">Added at</span>
<span class="title is-6">{{
$filters.time(artist.time_added, 'L LT')
$filters.datetime(artist.time_added)
}}</span>
</p>
</div>

View File

@ -23,6 +23,12 @@
composer.track_count
}}</a>
</p>
<p>
<span class="heading">Length</span>
<span class="title is-6">{{
$filters.durationInHours(composer.length_ms)
}}</span>
</p>
</div>
<footer class="card-footer">
<a class="card-footer-item has-text-dark" @click="queue_add">

View File

@ -11,6 +11,22 @@
genre.name
}}</a>
</p>
<div class="content is-small">
<p>
<span class="heading">Albums</span>
<span class="title is-6">{{ genre.album_count }}</span>
</p>
<p>
<span class="heading">Tracks</span>
<span class="title is-6">{{ genre.track_count }}</span>
</p>
<p>
<span class="heading">Length</span>
<span class="title is-6">{{
$filters.durationInHours(genre.length_ms)
}}</span>
</p>
</div>
</div>
<footer class="card-footer">
<a class="card-footer-item has-text-dark" @click="queue_add">

View File

@ -56,7 +56,7 @@
<p>
<span class="heading">Length</span>
<span class="title is-6">{{
$filters.duration(item.length_ms)
$filters.durationInHours(item.length_ms)
}}</span>
</p>
<p>

View File

@ -48,7 +48,7 @@
<p v-if="track.date_released">
<span class="heading">Release date</span>
<span class="title is-6">{{
$filters.time(track.date_released, 'L')
$filters.date(track.date_released)
}}</span>
</p>
<p v-else-if="track.year > 0">
@ -70,7 +70,7 @@
<p>
<span class="heading">Length</span>
<span class="title is-6">{{
$filters.duration(track.length_ms)
$filters.durationInHours(track.length_ms)
}}</span>
</p>
<p>
@ -107,7 +107,7 @@
<p>
<span class="heading">Added at</span>
<span class="title is-6">{{
$filters.time(track.time_added, 'L LT')
$filters.datetime(track.time_added)
}}</span>
</p>
<p>

View File

@ -11,7 +11,7 @@
<b>{{ album.artists[0].name }}</b>
</h2>
<h2 class="subtitle is-7 has-text-grey has-text-weight-normal">
({{ album.album_type }}, {{ $filters.time(album.release_date, 'L') }})
({{ album.album_type }}, {{ $filters.date(album.release_date) }})
</h2>
</div>
<div class="media-right">

View File

@ -32,7 +32,7 @@
<p>
<span class="heading">Release date</span>
<span class="title is-6">{{
$filters.time(album.release_date, 'L')
$filters.date(album.release_date)
}}</span>
</p>
<p>

View File

@ -28,7 +28,7 @@
<p>
<span class="heading">Release date</span>
<span class="title is-6">{{
$filters.time(album.release_date, 'L')
$filters.date(album.release_date)
}}</span>
</p>
<p>
@ -40,7 +40,7 @@
<p>
<span class="heading">Length</span>
<span class="title is-6">{{
$filters.duration(track.duration_ms)
$filters.durationInHours(track.duration_ms)
}}</span>
</p>
<p>

View File

@ -1,25 +1,47 @@
import moment from 'moment'
import momentDurationFormatSetup from 'moment-duration-format'
momentDurationFormatSetup(moment)
import { DateTime, Duration } from 'luxon'
export const filters = {
duration: function (value, format) {
if (format) {
return moment.duration(value).format(format)
durationInHours: function (value_ms) {
const seconds = Math.floor(value_ms / 1000)
if (seconds > 3600) {
return Duration.fromObject({ seconds: seconds })
.shiftTo('hours', 'minutes', 'seconds')
.toFormat('hh:mm:ss')
}
return moment.duration(value).format('hh:*mm:ss')
return Duration.fromObject({ seconds: seconds })
.shiftTo('minutes', 'seconds')
.toFormat('mm:ss')
},
time: function (value, format) {
if (format) {
return moment(value).format(format)
durationInDays: function (value_ms) {
const minutes = Math.floor(value_ms / 60000)
if (minutes > 1440) {
// 60 * 24
return Duration.fromObject({ minutes: minutes })
.shiftTo('days', 'hours', 'minutes')
.toHuman()
} else if (minutes > 60) {
return Duration.fromObject({ minutes: minutes })
.shiftTo('hours', 'minutes')
.toHuman()
}
return moment(value).format()
return Duration.fromObject({ minutes: minutes })
.shiftTo('minutes')
.toHuman()
},
timeFromNow: function (value, withoutSuffix) {
return moment(value).fromNow(withoutSuffix)
date: function (value) {
return DateTime.fromISO(value).toLocaleString(DateTime.DATE_FULL)
},
datetime: function (value) {
return DateTime.fromISO(value).toLocaleString(DateTime.DATETIME_MED)
},
timeFromNow: function (value) {
var diff = DateTime.now().diff(DateTime.fromISO(value))
return this.durationInDays(diff.as('milliseconds'))
},
number: function (value) {

View File

@ -132,10 +132,12 @@ section.hero + section.fd-content {
.fd-page {
margin-top: 3.25rem;
margin-bottom: 3.25rem;
}
.fd-page-with-tabs {
margin-top: 6.25rem !important;
margin-bottom: 3.25rem;
}
/* Set minimum height to hide "option" section */

View File

@ -61,20 +61,15 @@
<tr>
<th>Total playtime</th>
<td class="has-text-right">
{{
$filters.duration(
library.db_playtime * 1000,
'y [years], d [days], h [hours], m [minutes]'
)
}}
{{ $filters.durationInDays(library.db_playtime * 1000) }}
</td>
</tr>
<tr>
<th>Library updated</th>
<td class="has-text-right">
{{ $filters.timeFromNow(library.updated_at) }}
{{ $filters.timeFromNow(library.updated_at) }} ago
<span class="has-text-grey"
>({{ $filters.time(library.updated_at, 'lll') }})</span
>({{ $filters.datetime(library.updated_at) }})</span
>
</td>
</tr>
@ -83,7 +78,7 @@
<td class="has-text-right">
{{ $filters.timeFromNow(library.started_at, true) }}
<span class="has-text-grey"
>({{ $filters.time(library.started_at, 'll') }})</span
>({{ $filters.datetime(library.started_at) }})</span
>
</td>
</tr>

View File

@ -3,7 +3,7 @@
<content-with-heading>
<template #heading-left>
<p class="title is-4">
{{ name }}
{{ composer.name }}
</p>
</template>
<template #heading-right>
@ -24,14 +24,16 @@
</template>
<template #content>
<p class="heading has-text-centered-mobile">
{{ albums_list.total }} albums |
<a class="has-text-link" @click="open_tracks">tracks</a>
{{ composer.album_count }} albums |
<a class="has-text-link" @click="open_tracks"
>{{ composer.track_count }} tracks</a
>
</p>
<list-albums :albums="albums_list" :hide_group_title="true" />
<modal-dialog-composer
:show="show_composer_details_modal"
:composer="{ name: name }"
:composer="composer"
@close="show_composer_details_modal = false"
/>
</template>
@ -48,12 +50,15 @@ import { GroupByList } from '@/lib/GroupByList'
const dataObject = {
load: function (to) {
return webapi.library_composer(to.params.composer)
return Promise.all([
webapi.library_composer(to.params.composer),
webapi.library_composer_albums(to.params.composer)
])
},
set: function (vm, response) {
vm.name = vm.$route.params.composer
vm.albums_list = new GroupByList(response.data.albums)
vm.composer = response[0].data
vm.albums_list = new GroupByList(response[1].data.albums)
}
}
@ -80,7 +85,7 @@ export default {
data() {
return {
name: '',
composer: {},
albums_list: new GroupByList(),
show_composer_details_modal: false
}
@ -90,13 +95,13 @@ export default {
open_tracks: function () {
this.$router.push({
name: 'ComposerTracks',
params: { composer: this.name }
params: { composer: this.composer.name }
})
},
play: function () {
webapi.player_play_expression(
'composer is "' + this.name + '" and media_kind is music',
'composer is "' + this.composer.name + '" and media_kind is music',
true
)
}

View File

@ -3,7 +3,7 @@
<content-with-heading>
<template #heading-left>
<p class="title is-4">
{{ composer }}
{{ composer.name }}
</p>
</template>
<template #heading-right>
@ -24,13 +24,15 @@
</template>
<template #content>
<p class="heading has-text-centered-mobile">
<a class="has-text-link" @click="open_albums">albums</a> |
{{ tracks.total }} tracks
<a class="has-text-link" @click="open_albums"
>{{ composer.album_count }} albums</a
>
| {{ composer.track_count }} tracks
</p>
<list-tracks :tracks="tracks.items" :expression="play_expression" />
<modal-dialog-composer
:show="show_composer_details_modal"
:composer="{ name: composer }"
:composer="composer"
@close="show_composer_details_modal = false"
/>
</template>
@ -46,12 +48,15 @@ import webapi from '@/webapi'
const dataObject = {
load: function (to) {
return webapi.library_composer_tracks(to.params.composer)
return Promise.all([
webapi.library_composer(to.params.composer),
webapi.library_composer_tracks(to.params.composer)
])
},
set: function (vm, response) {
vm.composer = vm.$route.params.composer
vm.tracks = response.data.tracks
vm.composer = response[0].data
vm.tracks = response[1].data.tracks
}
}
@ -79,7 +84,7 @@ export default {
data() {
return {
tracks: { items: [] },
composer: '',
composer: {},
show_composer_details_modal: false
}
@ -87,7 +92,7 @@ export default {
computed: {
play_expression() {
return 'composer is "' + this.composer + '" and media_kind is music'
return 'composer is "' + this.composer.name + '" and media_kind is music'
}
},
@ -96,7 +101,7 @@ export default {
this.show_details_modal = false
this.$router.push({
name: 'ComposerAlbums',
params: { composer: this.composer }
params: { composer: this.composer.name }
})
},

View File

@ -27,7 +27,7 @@ import { byName, GroupByList } from '@/lib/GroupByList'
const dataObject = {
load: function (to) {
return webapi.library_composers()
return webapi.library_composers('music')
},
set: function (vm, response) {

View File

@ -6,7 +6,7 @@
</template>
<template #heading-left>
<p class="title is-4">
{{ name }}
{{ genre.name }}
</p>
</template>
<template #heading-right>
@ -27,13 +27,15 @@
</template>
<template #content>
<p class="heading has-text-centered-mobile">
{{ albums_list.total }} albums |
<a class="has-text-link" @click="open_tracks">tracks</a>
{{ genre.album_count }} albums |
<a class="has-text-link" @click="open_tracks"
>{{ genre.track_count }} tracks</a
>
</p>
<list-albums :albums="albums_list" />
<modal-dialog-genre
:show="show_genre_details_modal"
:genre="{ name: name }"
:genre="genre"
@close="show_genre_details_modal = false"
/>
</template>
@ -51,12 +53,15 @@ import { bySortName, GroupByList } from '@/lib/GroupByList'
const dataObject = {
load: function (to) {
return webapi.library_genre(to.params.genre)
return Promise.all([
webapi.library_genre(to.params.genre),
webapi.library_genre_albums(to.params.genre)
])
},
set: function (vm, response) {
vm.name = vm.$route.params.genre
vm.albums_list = new GroupByList(response.data.albums)
vm.genre = response[0].data
vm.albums_list = new GroupByList(response[1].data.albums)
vm.albums_list.group(bySortName('name_sort'))
}
}
@ -89,7 +94,7 @@ export default {
data() {
return {
name: '',
genre: {},
albums_list: new GroupByList(),
show_genre_details_modal: false
@ -99,12 +104,15 @@ export default {
methods: {
open_tracks: function () {
this.show_details_modal = false
this.$router.push({ name: 'GenreTracks', params: { genre: this.name } })
this.$router.push({
name: 'GenreTracks',
params: { genre: this.genre.name }
})
},
play: function () {
webapi.player_play_expression(
'genre is "' + this.name + '" and media_kind is music',
'genre is "' + this.genre.name + '" and media_kind is music',
true
)
}

View File

@ -6,7 +6,7 @@
</template>
<template #heading-left>
<p class="title is-4">
{{ genre }}
{{ genre.name }}
</p>
</template>
<template #heading-right>
@ -27,13 +27,15 @@
</template>
<template #content>
<p class="heading has-text-centered-mobile">
<a class="has-text-link" @click="open_genre">albums</a> |
{{ tracks.total }} tracks
<a class="has-text-link" @click="open_genre"
>{{ genre.album_count }} albums</a
>
| {{ genre.track_count }} tracks
</p>
<list-tracks :tracks="tracks.items" :expression="expression" />
<modal-dialog-genre
:show="show_genre_details_modal"
:genre="{ name: genre }"
:genre="genre"
@close="show_genre_details_modal = false"
/>
</template>
@ -50,12 +52,15 @@ import webapi from '@/webapi'
const dataObject = {
load: function (to) {
return webapi.library_genre_tracks(to.params.genre)
return Promise.all([
webapi.library_genre(to.params.genre),
webapi.library_genre_tracks(to.params.genre)
])
},
set: function (vm, response) {
vm.genre = vm.$route.params.genre
vm.tracks = response.data.tracks
vm.genre = response[0].data
vm.tracks = response[1].data.tracks
}
}
@ -102,14 +107,14 @@ export default {
},
expression() {
return 'genre is "' + this.genre + '" and media_kind is music'
return 'genre is "' + this.genre.name + '" and media_kind is music'
}
},
methods: {
open_genre: function () {
this.show_details_modal = false
this.$router.push({ name: 'Genre', params: { genre: this.genre } })
this.$router.push({ name: 'Genre', params: { genre: this.genre.name } })
},
play: function () {

View File

@ -27,7 +27,7 @@ import { byName, GroupByList } from '@/lib/GroupByList'
const dataObject = {
load: function (to) {
return webapi.library_genres()
return webapi.library_genres('music')
},
set: function (vm, response) {

View File

@ -14,6 +14,7 @@
<div class="container has-text-centered">
<p class="control has-text-centered fd-progress-now-playing">
<Slider
ref="slider"
v-model="item_progress_ms"
:min="0"
:max="state.item_length_ms"
@ -22,6 +23,8 @@
:disabled="state.state === 'stop'"
:classes="{ target: 'seek-slider' }"
@change="seek"
@start="start_dragging"
@end="end_dragging"
/>
<!--range-slider
class="seek-slider fd-has-action"
@ -35,8 +38,8 @@
</p>
<p class="content">
<span
>{{ $filters.duration(item_progress_ms) }} /
{{ $filters.duration(now_playing.length_ms) }}</span
>{{ $filters.durationInHours(item_progress_ms) }} /
{{ $filters.durationInHours(now_playing.length_ms) }}</span
>
</p>
</div>
@ -101,6 +104,7 @@ export default {
return {
item_progress_ms: 0,
interval_id: 0,
is_dragged: false,
show_details_modal: false,
selected_item: {}
@ -157,6 +161,10 @@ export default {
}
},
mounted: function () {
console.log(this.$refs.slider)
},
created() {
this.item_progress_ms = this.state.item_progress_ms
webapi.player_status().then(({ data }) => {
@ -176,7 +184,19 @@ export default {
methods: {
tick: function () {
this.item_progress_ms += 1000
if (!this.is_dragged) {
this.item_progress_ms += 1000
}
},
start_dragging: function () {
console.log('@start')
this.is_dragged = true
},
end_dragging: function () {
console.log('@end')
this.is_dragged = false
},
seek: function (newPosition) {

View File

@ -50,7 +50,7 @@
:context_uri="album.uri"
>
<template #actions>
<a @click="open_track_dialog(track)">
<a @click.prevent.stop="open_track_dialog(track)">
<span class="icon has-text-dark"
><i class="mdi mdi-dots-vertical mdi-18px"
/></span>

View File

@ -26,7 +26,7 @@
</p>
</template>
<template #actions>
<a @click="open_album_dialog(album)">
<a @click.prevent.stop="open_album_dialog(album)">
<span class="icon has-text-dark"
><i class="mdi mdi-dots-vertical mdi-18px"
/></span>
@ -65,7 +65,7 @@
:playlist="playlist"
>
<template #actions>
<a @click="open_playlist_dialog(playlist)">
<a @click.prevent.stop="open_playlist_dialog(playlist)">
<span class="icon has-text-dark"
><i class="mdi mdi-dots-vertical mdi-18px"
/></span>

View File

@ -13,7 +13,7 @@
:playlist="playlist"
>
<template #actions>
<a @click="open_playlist_dialog(playlist)">
<a @click.prevent.stop="open_playlist_dialog(playlist)">
<span class="icon has-text-dark"
><i class="mdi mdi-dots-vertical mdi-18px"
/></span>

View File

@ -25,7 +25,7 @@
</p>
</template>
<template #actions>
<a @click="open_album_dialog(album)">
<a @click.prevent.stop="open_album_dialog(album)">
<span class="icon has-text-dark"
><i class="mdi mdi-dots-vertical mdi-18px"
/></span>

View File

@ -34,7 +34,7 @@
:context_uri="playlist.uri"
>
<template #actions>
<a @click="open_track_dialog(item.track)">
<a @click.prevent.stop="open_track_dialog(item.track)">
<span class="icon has-text-dark"
><i class="mdi mdi-dots-vertical mdi-18px"
/></span>

View File

@ -53,7 +53,7 @@
:context_uri="track.uri"
>
<template #actions>
<a @click="open_track_dialog(track)">
<a @click.prevent.stop="open_track_dialog(track)">
<span class="icon has-text-dark"
><i class="mdi mdi-dots-vertical mdi-18px"
/></span>
@ -103,7 +103,7 @@
:artist="artist"
>
<template #actions>
<a @click="open_artist_dialog(artist)">
<a @click.prevent.stop="open_artist_dialog(artist)">
<span class="icon has-text-dark"
><i class="mdi mdi-dots-vertical mdi-18px"
/></span>
@ -164,7 +164,7 @@
</p>
</template>
<template #actions>
<a @click="open_album_dialog(album)">
<a @click.prevent.stop="open_album_dialog(album)">
<span class="icon has-text-dark"
><i class="mdi mdi-dots-vertical mdi-18px"
/></span>
@ -213,7 +213,7 @@
:playlist="playlist"
>
<template #actions>
<a @click="open_playlist_dialog(playlist)">
<a @click.prevent.stop="open_playlist_dialog(playlist)">
<span class="icon has-text-dark"
><i class="mdi mdi-dots-vertical mdi-18px"
/></span>

View File

@ -292,15 +292,20 @@ export default {
})
},
library_genres() {
return axios.get('./api/library/genres')
library_genres(media_kind = undefined) {
return axios.get('./api/library/genres', {
params: { media_kind: media_kind }
})
},
library_genre(genre) {
return axios.get(`./api/library/genres/${encodeURIComponent(genre)}`)
},
library_genre_albums(genre) {
const genreParams = {
type: 'albums',
media_kind: 'music',
expression: 'genre is "' + genre + '"'
expression: `genre is "${genre}" and media_kind is music`
}
return axios.get('./api/search', {
params: genreParams
@ -310,8 +315,7 @@ export default {
library_genre_tracks(genre) {
const genreParams = {
type: 'tracks',
media_kind: 'music',
expression: 'genre is "' + genre + '"'
expression: `genre is "${genre}" and media_kind is music`
}
return axios.get('./api/search', {
params: genreParams
@ -329,15 +333,20 @@ export default {
})
},
library_composers() {
return axios.get('./api/library/composers')
library_composers(media_kind = undefined) {
return axios.get('./api/library/composers', {
params: { media_kind: media_kind }
})
},
library_composer(composer) {
return axios.get(`./api/library/composers/${encodeURIComponent(composer)}`)
},
library_composer_albums(composer) {
const params = {
type: 'albums',
media_kind: 'music',
expression: 'composer is "' + composer + '"'
expression: `composer is "${composer}" and media_kind is music`
}
return axios.get('./api/search', {
params: params
@ -347,8 +356,7 @@ export default {
library_composer_tracks(composer) {
const params = {
type: 'tracks',
media_kind: 'music',
expression: 'composer is "' + composer + '"'
expression: `composer is "${composer}" and media_kind is music`
}
return axios.get('./api/search', {
params: params