[web-src] Add settings page for artwork providers

This commit is contained in:
chme 2020-03-14 14:13:37 +01:00
parent 08b2eb8d4c
commit a0cf9560a4
6 changed files with 305 additions and 158 deletions

View File

@ -0,0 +1,113 @@
<template>
<div class="field">
<label class="checkbox">
<input type="checkbox"
:checked="value"
@change="set_update_timer"
ref="settings_checkbox">
<slot name="label"></slot>
<i class="is-size-7"
:class="{
'has-text-info': statusUpdate === 'success',
'has-text-danger': statusUpdate === 'error'
}"> {{ info }}</i>
</label>
<p class="help" v-if="$slots['info']">
<slot name="info"></slot>
</p>
</div>
</template>
<script>
import webapi from '@/webapi'
import * as types from '@/store/mutation_types'
export default {
name: 'SettingsCheckbox',
props: ['category_name', 'option_name'],
data () {
return {
timerDelay: 2000,
timerId: -1,
// <empty>: default/no changes, 'success': update succesful, 'error': update failed
statusUpdate: ''
}
},
computed: {
category () {
return this.$store.state.settings.categories.find(elem => elem.name === this.category_name)
},
option () {
if (!this.category) {
return {}
}
return this.category.options.find(elem => elem.name === this.option_name)
},
value () {
return this.option.value
},
info () {
if (this.statusUpdate === 'success') {
return '(setting saved)'
} else if (this.statusUpdate === 'error') {
return '(error saving setting)'
}
return ''
}
},
methods: {
set_update_timer () {
if (this.timerId > 0) {
window.clearTimeout(this.timerId)
this.timerId = -1
}
this.statusUpdate = ''
const newValue = this.$refs.settings_checkbox.checked
if (newValue !== this.value) {
this.timerId = window.setTimeout(this.update_setting, this.timerDelay)
}
},
update_setting () {
this.timerId = -1
const newValue = this.$refs.settings_checkbox.checked
if (newValue === this.value) {
this.statusUpdate = ''
return
}
const option = {
category: this.category.name,
name: this.option_name,
value: newValue
}
webapi.settings_update(this.category.name, option).then(() => {
this.$store.commit(types.UPDATE_SETTINGS_OPTION, option)
this.statusUpdate = 'success'
}).catch(() => {
this.statusUpdate = 'error'
this.$refs.settings_checkbox.checked = this.value
}).finally(() => {
this.timerId = window.setTimeout(this.clear_status, this.timerDelay)
})
},
clear_status: function () {
this.statusUpdate = ''
}
}
}
</script>
<style>
</style>

View File

@ -0,0 +1,117 @@
<template>
<fieldset :disabled="disabled">
<div class="field">
<label class="label has-text-weight-normal">
<slot name="label"></slot>
<i class="is-size-7"
:class="{
'has-text-info': statusUpdate === 'success',
'has-text-danger': statusUpdate === 'error'
}"> {{ info }}</i>
</label>
<div class="control">
<input class="input" type="text" :placeholder="placeholder"
:value="value"
@input="set_update_timer"
ref="settings_text">
</div>
<p class="help" v-if="$slots['info']">
<slot name="info"></slot>
</p>
</div>
</fieldset>
</template>
<script>
import webapi from '@/webapi'
import * as types from '@/store/mutation_types'
export default {
name: 'SettingsTextfield',
props: ['category_name', 'option_name', 'placeholder', 'disabled'],
data () {
return {
timerDelay: 2000,
timerId: -1,
// <empty>: default/no changes, 'success': update succesful, 'error': update failed
statusUpdate: ''
}
},
computed: {
category () {
return this.$store.state.settings.categories.find(elem => elem.name === this.category_name)
},
option () {
if (!this.category) {
return {}
}
return this.category.options.find(elem => elem.name === this.option_name)
},
value () {
return this.option.value
},
info () {
if (this.statusUpdate === 'success') {
return '(setting saved)'
} else if (this.statusUpdate === 'error') {
return '(error saving setting)'
}
return ''
}
},
methods: {
set_update_timer () {
if (this.timerId > 0) {
window.clearTimeout(this.timerId)
this.timerId = -1
}
this.statusUpdate = ''
const newValue = this.$refs.settings_text.value
if (newValue !== this.value) {
this.timerId = window.setTimeout(this.update_setting, this.timerDelay)
}
},
update_setting () {
this.timerId = -1
const newValue = this.$refs.settings_text.value
if (newValue === this.value) {
this.statusUpdate = ''
return
}
const option = {
category: this.category.name,
name: this.option_name,
value: newValue
}
webapi.settings_update(this.category.name, option).then(() => {
this.$store.commit(types.UPDATE_SETTINGS_OPTION, option)
this.statusUpdate = 'success'
}).catch(() => {
this.statusUpdate = 'error'
this.$refs.settings_text.value = this.value
}).finally(() => {
this.timerId = window.setTimeout(this.clear_status, this.timerDelay)
})
},
clear_status: function () {
this.statusUpdate = ''
}
}
}
</script>
<style>
</style>

View File

@ -15,6 +15,11 @@
<span class="">Remotes &amp; Outputs</span> <span class="">Remotes &amp; Outputs</span>
</a> </a>
</router-link> </router-link>
<router-link tag="li" to="/settings/artwork" active-class="is-active">
<a>
<span class="">Artwork</span>
</a>
</router-link>
<router-link tag="li" to="/settings/online-services" active-class="is-active"> <router-link tag="li" to="/settings/online-services" active-class="is-active">
<a> <a>
<span class="">Online Services</span> <span class="">Online Services</span>

View File

@ -0,0 +1,50 @@
<template>
<div>
<tabs-settings></tabs-settings>
<content-with-heading>
<template slot="heading-left">
<div class="title is-4">Artwork</div>
</template>
<template slot="content">
<div class="content">
<p>
forked-daapd supports PNG and JPEG artwork which is either placed as separate image files in the library,
embedded in the media files or made available online by radio stations.
</p>
<p>In addition to that, you can enable fetching artwork from the following artwork providers:</p>
</div>
<settings-checkbox category_name="artwork" option_name="use_artwork_source_spotify" v-if="spotify.enabled">
<template slot="label"> Spotify</template>
</settings-checkbox>
<settings-checkbox category_name="artwork" option_name="use_artwork_source_discogs">
<template slot="label"> Discogs (<a href="https://www.discogs.com/">https://www.discogs.com/</a>)</template>
</settings-checkbox>
<settings-checkbox category_name="artwork" option_name="use_artwork_source_coverartarchive">
<template slot="label"> Cover Art Archive (<a href="https://coverartarchive.org/">https://coverartarchive.org/</a>)</template>
</settings-checkbox>
</template>
</content-with-heading>
</div>
</template>
<script>
import ContentWithHeading from '@/templates/ContentWithHeading'
import TabsSettings from '@/components/TabsSettings'
import SettingsCheckbox from '@/components/SettingsCheckbox'
export default {
name: 'SettingsPageArtwork',
components: { ContentWithHeading, TabsSettings, SettingsCheckbox },
computed: {
spotify () {
return this.$store.state.spotify
}
}
}
</script>
<style>
</style>

View File

@ -8,36 +8,15 @@
</template> </template>
<template slot="content"> <template slot="content">
<div class="field"> <settings-checkbox category_name="webinterface" option_name="show_composer_now_playing">
<label class="checkbox"> <template slot="label"> Show composer</template>
<input type="checkbox" :checked="settings_option_show_composer_now_playing" @change="set_timer_show_composer_now_playing" ref="checkbox_show_composer"> <template slot="info">If enabled the composer of the current playing track is shown on the &quot;now playing page&quot;</template>
Show composer </settings-checkbox>
<i class="is-size-7" <settings-textfield category_name="webinterface" option_name="show_composer_for_genre"
:class="{ :disabled="!settings_option_show_composer_now_playing"
'has-text-info': statusUpdateShowComposerNowPlaying === 'success', placeholder="Genres">
'has-text-danger': statusUpdateShowComposerNowPlaying === 'error' <template slot="label">Show composer only for listed genres</template>
}">{{ info_option_show_composer_now_playing }}</i> <template slot="info">
</label>
<p class="help has-text-justified">
If enabled the composer of the current playing track is shown on the &quot;now playing page&quot;
</p>
</div>
<fieldset :disabled="!settings_option_show_composer_now_playing">
<div class="field">
<label class="label has-text-weight-normal">
Show composer only for listed genres
<i class="is-size-7"
:class="{
'has-text-info': statusUpdateShowComposerForGenre === 'success',
'has-text-danger': statusUpdateShowComposerForGenre === 'error'
}">{{ info_option_show_composer_for_genre }}</i>
</label>
<div class="control">
<input class="input" type="text" placeholder="Genres"
:value="settings_option_show_composer_for_genre"
@input="set_timer_show_composer_for_genre"
ref="field_composer_for_genre">
</div>
<p class="help"> <p class="help">
Comma separated list of genres the composer should be displayed on the &quot;now playing page&quot;. Comma separated list of genres the composer should be displayed on the &quot;now playing page&quot;.
</p> </p>
@ -49,8 +28,8 @@
For example setting to <code>classical, soundtrack</code> will show the composer for tracks with For example setting to <code>classical, soundtrack</code> will show the composer for tracks with
a genre tag of &quot;Contemporary Classical&quot;.<br> a genre tag of &quot;Contemporary Classical&quot;.<br>
</p> </p>
</div> </template>
</fieldset> </settings-textfield>
</template> </template>
</content-with-heading> </content-with-heading>
</div> </div>
@ -59,140 +38,17 @@
<script> <script>
import ContentWithHeading from '@/templates/ContentWithHeading' import ContentWithHeading from '@/templates/ContentWithHeading'
import TabsSettings from '@/components/TabsSettings' import TabsSettings from '@/components/TabsSettings'
import webapi from '@/webapi' import SettingsCheckbox from '@/components/SettingsCheckbox'
import * as types from '@/store/mutation_types' import SettingsTextfield from '@/components/SettingsTextfield'
export default { export default {
name: 'SettingsPageWebinterface', name: 'SettingsPageWebinterface',
components: { ContentWithHeading, TabsSettings }, components: { ContentWithHeading, TabsSettings, SettingsCheckbox, SettingsTextfield },
data () {
return {
timerDelay: 2000,
timerIdShowComposerNowPlaying: -1,
timerIdShowComposerForGenre: -1,
// <empty>: default/no changes, 'success': update succesful, 'error': update failed
statusUpdateShowComposerNowPlaying: '',
statusUpdateShowComposerForGenre: ''
}
},
computed: { computed: {
settings_category_webinterface () {
return this.$store.getters.settings_webinterface
},
settings_option_show_composer_now_playing () { settings_option_show_composer_now_playing () {
return this.$store.getters.settings_option_show_composer_now_playing return this.$store.getters.settings_option_show_composer_now_playing
},
settings_option_show_composer_for_genre () {
return this.$store.getters.settings_option_show_composer_for_genre
},
info_option_show_composer_for_genre () {
if (this.statusUpdateShowComposerForGenre === 'success') {
return '(setting saved)'
} else if (this.statusUpdateShowComposerForGenre === 'error') {
return '(error saving setting)'
}
return ''
},
info_option_show_composer_now_playing () {
if (this.statusUpdateShowComposerNowPlaying === 'success') {
return '(setting saved)'
} else if (this.statusUpdateShowComposerNowPlaying === 'error') {
return '(error saving setting)'
}
return ''
} }
},
methods: {
set_timer_show_composer_now_playing () {
if (this.timerIdShowComposerNowPlaying > 0) {
window.clearTimeout(this.timerIdShowComposerNowPlaying)
this.timerIdShowComposerNowPlaying = -1
}
this.statusUpdateShowComposerNowPlaying = ''
const newValue = this.$refs.checkbox_show_composer.checked
if (newValue !== this.settings_option_show_composer_now_playing) {
this.timerIdShowComposerNowPlaying = window.setTimeout(this.update_show_composer_now_playing, this.timerDelay)
}
},
update_show_composer_now_playing () {
this.timerIdShowComposerNowPlaying = -1
const newValue = this.$refs.checkbox_show_composer.checked
if (newValue === this.settings_option_show_composer_now_playing) {
this.statusUpdateShowComposerNowPlaying = ''
return
}
const option = {
category: this.settings_category_webinterface.name,
name: 'show_composer_now_playing',
value: newValue
}
webapi.settings_update(this.settings_category_webinterface.name, option).then(() => {
this.$store.commit(types.UPDATE_SETTINGS_OPTION, option)
this.statusUpdateShowComposerNowPlaying = 'success'
}).catch(() => {
this.statusUpdateShowComposerNowPlaying = 'error'
this.$refs.checkbox_show_composer.checked = this.settings_option_show_composer_now_playing
}).finally(() => {
this.timerIdShowComposerNowPlaying = window.setTimeout(this.clear_status_show_composer_now_playing, this.timerDelay)
})
},
set_timer_show_composer_for_genre () {
if (this.timerIdShowComposerForGenre > 0) {
window.clearTimeout(this.timerIdShowComposerForGenre)
this.timerIdShowComposerForGenre = -1
}
this.statusUpdateShowComposerForGenre = ''
const newValue = this.$refs.field_composer_for_genre.value
if (newValue !== this.settings_option_show_composer_for_genre) {
this.timerIdShowComposerForGenre = window.setTimeout(this.update_show_composer_for_genre, this.timerDelay)
}
},
update_show_composer_for_genre () {
this.timerIdShowComposerForGenre = -1
const newValue = this.$refs.field_composer_for_genre.value
if (newValue === this.settings_option_show_composer_for_genre) {
this.statusUpdateShowComposerForGenre = ''
return
}
const option = {
category: this.settings_category_webinterface.name,
name: 'show_composer_for_genre',
value: newValue
}
webapi.settings_update(this.settings_category_webinterface.name, option).then(() => {
this.$store.commit(types.UPDATE_SETTINGS_OPTION, option)
this.statusUpdateShowComposerForGenre = 'success'
}).catch(() => {
this.statusUpdateShowComposerForGenre = 'error'
this.$refs.field_composer_for_genre.value = this.settings_option_show_composer_for_genre
}).finally(() => {
this.timerIdShowComposerForGenre = window.setTimeout(this.clear_status_show_composer_for_genre, this.timerDelay)
})
},
clear_status_show_composer_for_genre () {
this.statusUpdateShowComposerForGenre = ''
},
clear_status_show_composer_now_playing () {
this.statusUpdateShowComposerNowPlaying = ''
}
},
filters: {
} }
} }
</script> </script>

View File

@ -32,6 +32,7 @@ import SpotifyPageAlbum from '@/pages/SpotifyPageAlbum'
import SpotifyPagePlaylist from '@/pages/SpotifyPagePlaylist' import SpotifyPagePlaylist from '@/pages/SpotifyPagePlaylist'
import SpotifyPageSearch from '@/pages/SpotifyPageSearch' import SpotifyPageSearch from '@/pages/SpotifyPageSearch'
import SettingsPageWebinterface from '@/pages/SettingsPageWebinterface' import SettingsPageWebinterface from '@/pages/SettingsPageWebinterface'
import SettingsPageArtwork from '@/pages/SettingsPageArtwork'
import SettingsPageOnlineServices from '@/pages/SettingsPageOnlineServices' import SettingsPageOnlineServices from '@/pages/SettingsPageOnlineServices'
import SettingsPageRemotesOutputs from '@/pages/SettingsPageRemotesOutputs' import SettingsPageRemotesOutputs from '@/pages/SettingsPageRemotesOutputs'
@ -225,6 +226,11 @@ export const router = new VueRouter({
name: 'Settings Webinterface', name: 'Settings Webinterface',
component: SettingsPageWebinterface component: SettingsPageWebinterface
}, },
{
path: '/settings/artwork',
name: 'Settings Artwork',
component: SettingsPageArtwork
},
{ {
path: '/settings/online-services', path: '/settings/online-services',
name: 'Settings Online Services', name: 'Settings Online Services',