mirror of
https://github.com/owntone/owntone-server.git
synced 2025-02-03 01:46:02 -05:00
Merge pull request #875 from chme/web
Update player web interface v0.6.0
This commit is contained in:
commit
aee916a63f
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
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
2577
web-src/package-lock.json
generated
2577
web-src/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "forked-daapd-web",
|
"name": "forked-daapd-web",
|
||||||
"version": "0.5.6",
|
"version": "0.6.0",
|
||||||
"description": "forked-daapd web interface",
|
"description": "forked-daapd web interface",
|
||||||
"author": "chme <christian.meffert@googlemail.com>",
|
"author": "chme <christian.meffert@googlemail.com>",
|
||||||
"license": "GPL-2.0",
|
"license": "GPL-2.0",
|
||||||
@ -12,28 +12,28 @@
|
|||||||
"lint": "vue-cli-service lint"
|
"lint": "vue-cli-service lint"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "^0.19.0",
|
"axios": "^0.19.1",
|
||||||
"bulma": "^0.7.5",
|
"bulma": "^0.8.0",
|
||||||
"mdi": "^2.2.43",
|
"mdi": "^2.2.43",
|
||||||
"moment": "^2.24.0",
|
"moment": "^2.24.0",
|
||||||
"moment-duration-format": "^2.3.2",
|
"moment-duration-format": "^2.3.2",
|
||||||
"npm": "^6.11.2",
|
"npm": "^6.13.6",
|
||||||
"reconnectingwebsocket": "^1.0.0",
|
"reconnectingwebsocket": "^1.0.0",
|
||||||
"spotify-web-api-js": "^1.2.0",
|
"spotify-web-api-js": "^1.2.0",
|
||||||
"v-click-outside": "^2.1.4",
|
"v-click-outside": "^3.0.0",
|
||||||
"vue": "^2.6.10",
|
"vue": "^2.6.11",
|
||||||
"vue-infinite-loading": "^2.4.4",
|
"vue-infinite-loading": "^2.4.4",
|
||||||
"vue-progressbar": "^0.7.5",
|
"vue-progressbar": "^0.7.5",
|
||||||
"vue-range-slider": "^0.6.0",
|
"vue-range-slider": "^0.6.0",
|
||||||
"vue-router": "^3.1.3",
|
"vue-router": "^3.1.3",
|
||||||
"vuedraggable": "^2.23.0",
|
"vuedraggable": "^2.23.2",
|
||||||
"vuex": "^3.1.1"
|
"vuex": "^3.1.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@vue/cli-plugin-babel": "^3.11.0",
|
"@vue/cli-plugin-babel": "^3.12.1",
|
||||||
"@vue/cli-plugin-eslint": "^3.11.0",
|
"@vue/cli-plugin-eslint": "^3.12.1",
|
||||||
"@vue/cli-service": "^3.11.0",
|
"@vue/cli-service": "^3.12.1",
|
||||||
"@vue/eslint-config-standard": "^4.0.0",
|
"@vue/eslint-config-standard": "^4.0.0",
|
||||||
"vue-template-compiler": "^2.6.10"
|
"vue-template-compiler": "^2.6.11"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -101,7 +101,7 @@ export default {
|
|||||||
socket.onopen = function () {
|
socket.onopen = function () {
|
||||||
vm.$store.dispatch('add_notification', { text: 'Connection to server established', type: 'primary', topic: 'connection', timeout: 2000 })
|
vm.$store.dispatch('add_notification', { text: 'Connection to server established', type: 'primary', topic: 'connection', timeout: 2000 })
|
||||||
vm.reconnect_attempts = 0
|
vm.reconnect_attempts = 0
|
||||||
socket.send(JSON.stringify({ notify: ['update', 'database', 'player', 'options', 'outputs', 'volume', 'spotify'] }))
|
socket.send(JSON.stringify({ notify: ['update', 'database', 'player', 'options', 'outputs', 'volume', 'spotify', 'lastfm', 'pairing'] }))
|
||||||
|
|
||||||
vm.update_outputs()
|
vm.update_outputs()
|
||||||
vm.update_player_status()
|
vm.update_player_status()
|
||||||
@ -109,6 +109,8 @@ export default {
|
|||||||
vm.update_settings()
|
vm.update_settings()
|
||||||
vm.update_queue()
|
vm.update_queue()
|
||||||
vm.update_spotify()
|
vm.update_spotify()
|
||||||
|
vm.update_lastfm()
|
||||||
|
vm.update_pairing()
|
||||||
}
|
}
|
||||||
socket.onclose = function () {
|
socket.onclose = function () {
|
||||||
// vm.$store.dispatch('add_notification', { text: 'Connection closed', type: 'danger', timeout: 2000 })
|
// vm.$store.dispatch('add_notification', { text: 'Connection closed', type: 'danger', timeout: 2000 })
|
||||||
@ -134,6 +136,12 @@ export default {
|
|||||||
if (data.notify.includes('spotify')) {
|
if (data.notify.includes('spotify')) {
|
||||||
vm.update_spotify()
|
vm.update_spotify()
|
||||||
}
|
}
|
||||||
|
if (data.notify.includes('lastfm')) {
|
||||||
|
vm.update_lastfm()
|
||||||
|
}
|
||||||
|
if (data.notify.includes('pairing')) {
|
||||||
|
vm.update_pairing()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -173,6 +181,12 @@ export default {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
update_lastfm: function () {
|
||||||
|
webapi.lastfm().then(({ data }) => {
|
||||||
|
this.$store.commit(types.UPDATE_LASTFM, data)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
update_spotify: function () {
|
update_spotify: function () {
|
||||||
webapi.spotify().then(({ data }) => {
|
webapi.spotify().then(({ data }) => {
|
||||||
this.$store.commit(types.UPDATE_SPOTIFY, data)
|
this.$store.commit(types.UPDATE_SPOTIFY, data)
|
||||||
@ -185,6 +199,12 @@ export default {
|
|||||||
this.token_timer_id = window.setTimeout(this.update_spotify, 1000 * data.webapi_token_expires_in)
|
this.token_timer_id = window.setTimeout(this.update_spotify, 1000 * data.webapi_token_expires_in)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
update_pairing: function () {
|
||||||
|
webapi.pairing().then(({ data }) => {
|
||||||
|
this.$store.commit(types.UPDATE_PAIRING, data)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
<div class="media-content fd-has-action is-clipped" v-on:click="open_album">
|
<div class="media-content fd-has-action is-clipped" v-on:click="open_album">
|
||||||
<h1 class="title is-6">{{ album.name }}</h1>
|
<h1 class="title is-6">{{ album.name }}</h1>
|
||||||
<h2 class="subtitle is-7 has-text-grey"><b>{{ album.artists[0].name }}</b></h2>
|
<h2 class="subtitle is-7 has-text-grey"><b>{{ album.artists[0].name }}</b></h2>
|
||||||
|
<h2 class="subtitle is-7 has-text-grey has-text-weight-normal">({{ album.album_type }}, {{ album.release_date }})</h2>
|
||||||
</div>
|
</div>
|
||||||
<div class="media-right">
|
<div class="media-right">
|
||||||
<slot name="actions"></slot>
|
<slot name="actions"></slot>
|
||||||
|
41
web-src/src/components/TabsSettings.vue
Normal file
41
web-src/src/components/TabsSettings.vue
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
<template>
|
||||||
|
<section class="section fd-tabs-section">
|
||||||
|
<div class="container">
|
||||||
|
<div class="columns is-centered">
|
||||||
|
<div class="column is-four-fifths">
|
||||||
|
<div class="tabs is-centered is-small">
|
||||||
|
<ul>
|
||||||
|
<router-link tag="li" to="/settings/webinterface" active-class="is-active">
|
||||||
|
<a>
|
||||||
|
<span class="">Webinterface</span>
|
||||||
|
</a>
|
||||||
|
</router-link>
|
||||||
|
<router-link tag="li" to="/settings/remotes-outputs" active-class="is-active">
|
||||||
|
<a>
|
||||||
|
<span class="">Remotes & Outputs</span>
|
||||||
|
</a>
|
||||||
|
</router-link>
|
||||||
|
<router-link tag="li" to="/settings/online-services" active-class="is-active">
|
||||||
|
<a>
|
||||||
|
<span class="">Online Services</span>
|
||||||
|
</a>
|
||||||
|
</router-link>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'TabsSettings',
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
</style>
|
205
web-src/src/pages/SettingsPageOnlineServices.vue
Normal file
205
web-src/src/pages/SettingsPageOnlineServices.vue
Normal file
@ -0,0 +1,205 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<tabs-settings></tabs-settings>
|
||||||
|
|
||||||
|
<content-with-heading>
|
||||||
|
<template slot="heading-left">
|
||||||
|
<div class="title is-4">Spotify</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template slot="content">
|
||||||
|
<div class="notification is-size-7" v-if="!spotify.libspotify_installed">
|
||||||
|
<p>forked-daapd was either built without support for Spotify or libspotify is not installed.</p>
|
||||||
|
</div>
|
||||||
|
<div v-if="spotify.libspotify_installed">
|
||||||
|
<div class="notification is-size-7">
|
||||||
|
<b>You must have a Spotify premium account</b>. If you normally log into Spotify with your Facebook account you must first go to Spotify's web site where you can get the Spotify username and password that matches your account.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<p class="content">
|
||||||
|
<b>libspotify</b> - Login with your Spotify username and password
|
||||||
|
</p>
|
||||||
|
<p v-if="spotify.libspotify_logged_in" class="fd-has-margin-bottom">
|
||||||
|
Logged in as <b><code>{{ spotify.libspotify_user }}</code></b>
|
||||||
|
</p>
|
||||||
|
<form v-if="spotify.libspotify_installed && !spotify.libspotify_logged_in" @submit.prevent="login_libspotify">
|
||||||
|
<div class="field is-grouped">
|
||||||
|
<div class="control is-expanded">
|
||||||
|
<input class="input" type="text" placeholder="Username" v-model="libspotify.user">
|
||||||
|
<p class="help is-danger">{{ libspotify.errors.user }}</p>
|
||||||
|
</div>
|
||||||
|
<div class="control is-expanded">
|
||||||
|
<input class="input" type="password" placeholder="Password" v-model="libspotify.password">
|
||||||
|
<p class="help is-danger">{{ libspotify.errors.password }}</p>
|
||||||
|
</div>
|
||||||
|
<div class="control">
|
||||||
|
<button class="button is-info">Login</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<p class="help is-danger">{{ libspotify.errors.error }}</p>
|
||||||
|
<p class="help">
|
||||||
|
libspotify enables forked-daapd to play Spotify tracks.
|
||||||
|
</p>
|
||||||
|
<p class="help">
|
||||||
|
forked-daapd will not store your password, but will still be able to log you in automatically afterwards, because libspotify saves a login token.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="fd-has-margin-top">
|
||||||
|
<p class="content">
|
||||||
|
<b>Spotify Web API</b> - Grant access to the Spotify Web API
|
||||||
|
</p>
|
||||||
|
<p v-if="spotify.webapi_token_valid">
|
||||||
|
Access granted for <b><code>{{ spotify.webapi_user }}</code></b>
|
||||||
|
</p>
|
||||||
|
<p class="help is-danger" v-if="spotify_missing_scope.length > 0">
|
||||||
|
Please reauthorize Web API access to grant forked-daapd the following additional access rights:
|
||||||
|
<b><code>{{ spotify_missing_scope | join }}</code></b>
|
||||||
|
</p>
|
||||||
|
<div class="field fd-has-margin-top ">
|
||||||
|
<div class="control">
|
||||||
|
<a class="button" :class="{ 'is-info': !spotify.webapi_token_valid || spotify_missing_scope.length > 0 }" :href="spotify.oauth_uri">Authorize Web API access</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p class="help">
|
||||||
|
Access to the Spotify Web API enables scanning of your Spotify library. Required scopes are
|
||||||
|
<code>{{ spotify_required_scope | join }}</code>.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</content-with-heading>
|
||||||
|
|
||||||
|
<content-with-heading>
|
||||||
|
<template slot="heading-left">
|
||||||
|
<div class="title is-4">Last.fm</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template slot="content">
|
||||||
|
<div class="notification is-size-7" v-if="!lastfm.enabled">
|
||||||
|
<p>forked-daapd was built without support for Last.fm.</p>
|
||||||
|
</div>
|
||||||
|
<div v-if="lastfm.enabled">
|
||||||
|
<p class="content">
|
||||||
|
<b>Last.fm</b> - Login with your Last.fm username and password to enable scrobbling
|
||||||
|
</p>
|
||||||
|
<div v-if="lastfm.scrobbling_enabled">
|
||||||
|
<a class="button" @click="logoutLastfm">Stop scrobbling</a>
|
||||||
|
</div>
|
||||||
|
<div v-if="!lastfm.scrobbling_enabled">
|
||||||
|
<form @submit.prevent="login_lastfm">
|
||||||
|
<div class="field is-grouped">
|
||||||
|
<div class="control is-expanded">
|
||||||
|
<input class="input" type="text" placeholder="Username" v-model="lastfm_login.user">
|
||||||
|
<p class="help is-danger">{{ lastfm_login.errors.user }}</p>
|
||||||
|
</div>
|
||||||
|
<div class="control is-expanded">
|
||||||
|
<input class="input" type="password" placeholder="Password" v-model="lastfm_login.password">
|
||||||
|
<p class="help is-danger">{{ lastfm_login.errors.password }}</p>
|
||||||
|
</div>
|
||||||
|
<div class="control">
|
||||||
|
<button class="button is-info" type="submit">Login</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p class="help is-danger">{{ lastfm_login.errors.error }}</p>
|
||||||
|
<p class="help">
|
||||||
|
forked-daapd will not store your Last.fm username/password, only the session key. The session key does not expire.
|
||||||
|
</p>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</content-with-heading>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import ContentWithHeading from '@/templates/ContentWithHeading'
|
||||||
|
import TabsSettings from '@/components/TabsSettings'
|
||||||
|
import webapi from '@/webapi'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'SettingsPageOnlineServices',
|
||||||
|
components: { ContentWithHeading, TabsSettings },
|
||||||
|
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
libspotify: { user: '', password: '', errors: { user: '', password: '', error: '' } },
|
||||||
|
lastfm_login: { user: '', password: '', errors: { user: '', password: '', error: '' } }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
lastfm () {
|
||||||
|
return this.$store.state.lastfm
|
||||||
|
},
|
||||||
|
|
||||||
|
spotify () {
|
||||||
|
return this.$store.state.spotify
|
||||||
|
},
|
||||||
|
|
||||||
|
spotify_required_scope () {
|
||||||
|
if (this.spotify.webapi_token_valid && this.spotify.webapi_granted_scope && this.spotify.webapi_required_scope) {
|
||||||
|
return this.spotify.webapi_required_scope.split(' ')
|
||||||
|
}
|
||||||
|
return []
|
||||||
|
},
|
||||||
|
|
||||||
|
spotify_missing_scope () {
|
||||||
|
if (this.spotify.webapi_token_valid && this.spotify.webapi_granted_scope && this.spotify.webapi_required_scope) {
|
||||||
|
return this.spotify.webapi_required_scope.split(' ').filter(scope => this.spotify.webapi_granted_scope.indexOf(scope) < 0)
|
||||||
|
}
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
login_libspotify () {
|
||||||
|
webapi.spotify_login(this.libspotify).then(response => {
|
||||||
|
this.libspotify.user = ''
|
||||||
|
this.libspotify.password = ''
|
||||||
|
this.libspotify.errors.user = ''
|
||||||
|
this.libspotify.errors.password = ''
|
||||||
|
this.libspotify.errors.error = ''
|
||||||
|
|
||||||
|
if (!response.data.success) {
|
||||||
|
this.libspotify.errors.user = response.data.errors.user
|
||||||
|
this.libspotify.errors.password = response.data.errors.password
|
||||||
|
this.libspotify.errors.error = response.data.errors.error
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
login_lastfm () {
|
||||||
|
webapi.lastfm_login(this.lastfm_login).then(response => {
|
||||||
|
this.lastfm_login.user = ''
|
||||||
|
this.lastfm_login.password = ''
|
||||||
|
this.lastfm_login.errors.user = ''
|
||||||
|
this.lastfm_login.errors.password = ''
|
||||||
|
this.lastfm_login.errors.error = ''
|
||||||
|
|
||||||
|
if (!response.data.success) {
|
||||||
|
this.lastfm_login.errors.user = response.data.errors.user
|
||||||
|
this.lastfm_login.errors.password = response.data.errors.password
|
||||||
|
this.lastfm_login.errors.error = response.data.errors.error
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
logoutLastfm () {
|
||||||
|
webapi.lastfm_logout()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
filters: {
|
||||||
|
join (array) {
|
||||||
|
return array.join(', ')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
</style>
|
114
web-src/src/pages/SettingsPageRemotesOutputs.vue
Normal file
114
web-src/src/pages/SettingsPageRemotesOutputs.vue
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<tabs-settings></tabs-settings>
|
||||||
|
|
||||||
|
<content-with-heading>
|
||||||
|
<template slot="heading-left">
|
||||||
|
<div class="title is-4">Remote Pairing</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template slot="content">
|
||||||
|
<!-- Paring request active -->
|
||||||
|
<div class="notification" v-if="pairing.active">
|
||||||
|
<form v-on:submit.prevent="kickoff_pairing">
|
||||||
|
<label class="label has-text-weight-normal">
|
||||||
|
Remote pairing request from <b>{{ pairing.remote }}</b>
|
||||||
|
</label>
|
||||||
|
<div class="field is-grouped">
|
||||||
|
<div class="control">
|
||||||
|
<input class="input" type="text" placeholder="Enter pairing code" v-model="pairing_req.pin">
|
||||||
|
</div>
|
||||||
|
<div class="control">
|
||||||
|
<button class="button is-info" type="submit">Send</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<!-- No pairing requests -->
|
||||||
|
<div class="content" v-if="!pairing.active">
|
||||||
|
<p>No active pairing request.</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</content-with-heading>
|
||||||
|
|
||||||
|
<content-with-heading>
|
||||||
|
<template slot="heading-left">
|
||||||
|
<div class="title is-4">Device Verification</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template slot="content">
|
||||||
|
<p class="content">
|
||||||
|
If your Apple TV requires device verification then activate the device below and enter the PIN that the Apple TV displays.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div v-for="output in outputs" :key="output.id">
|
||||||
|
<div class="field">
|
||||||
|
<div class="control">
|
||||||
|
<label class="checkbox">
|
||||||
|
<input type="checkbox" v-model="output.selected" @change="output_toggle(output.id)"> {{ output.name }}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<form @submit.prevent="kickoff_verification" v-if="output.needs_auth_key" class="fd-has-margin-bottom">
|
||||||
|
<div class="field is-grouped">
|
||||||
|
<div class="control">
|
||||||
|
<input class="input" type="text" placeholder="Enter verification code" v-model="verification_req.pin">
|
||||||
|
</div>
|
||||||
|
<div class="control">
|
||||||
|
<button class="button is-info" type="submit">Verify</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</content-with-heading>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import ContentWithHeading from '@/templates/ContentWithHeading'
|
||||||
|
import TabsSettings from '@/components/TabsSettings'
|
||||||
|
import webapi from '@/webapi'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'SettingsPageRemotesOutputs',
|
||||||
|
components: { ContentWithHeading, TabsSettings },
|
||||||
|
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
pairing_req: { pin: '' },
|
||||||
|
verification_req: { pin: '' }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
pairing () {
|
||||||
|
return this.$store.state.pairing
|
||||||
|
},
|
||||||
|
|
||||||
|
outputs () {
|
||||||
|
return this.$store.state.outputs
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
kickoff_pairing () {
|
||||||
|
webapi.pairing_kickoff(this.pairing_req)
|
||||||
|
},
|
||||||
|
|
||||||
|
output_toggle (outputId) {
|
||||||
|
webapi.output_toggle(outputId)
|
||||||
|
},
|
||||||
|
|
||||||
|
kickoff_verification () {
|
||||||
|
webapi.verification_kickoff(this.verification_req)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
filters: {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
</style>
|
@ -1,15 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
|
<div>
|
||||||
|
<tabs-settings></tabs-settings>
|
||||||
|
|
||||||
<content-with-heading>
|
<content-with-heading>
|
||||||
<template slot="heading-left">
|
<template slot="heading-left">
|
||||||
<div class="title is-4">Settings</div>
|
<div class="title is-4">Now playing page</div>
|
||||||
</template>
|
|
||||||
|
|
||||||
<template slot="heading-right">
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template slot="content">
|
<template slot="content">
|
||||||
<div class="heading fd-has-margin-bottom">Now playing page</div>
|
|
||||||
|
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label class="checkbox">
|
<label class="checkbox">
|
||||||
<input type="checkbox" :checked="settings_option_show_composer_now_playing" @change="set_timer_show_composer_now_playing" ref="checkbox_show_composer">
|
<input type="checkbox" :checked="settings_option_show_composer_now_playing" @change="set_timer_show_composer_now_playing" ref="checkbox_show_composer">
|
||||||
@ -53,19 +51,20 @@
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
</content-with-heading>
|
</content-with-heading>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import ContentWithHeading from '@/templates/ContentWithHeading'
|
import ContentWithHeading from '@/templates/ContentWithHeading'
|
||||||
|
import TabsSettings from '@/components/TabsSettings'
|
||||||
import webapi from '@/webapi'
|
import webapi from '@/webapi'
|
||||||
import * as types from '@/store/mutation_types'
|
import * as types from '@/store/mutation_types'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'SettingsPageWebinterface',
|
name: 'SettingsPageWebinterface',
|
||||||
components: { ContentWithHeading },
|
components: { ContentWithHeading, TabsSettings },
|
||||||
|
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
|
@ -32,6 +32,8 @@ 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 SettingsPageOnlineServices from '@/pages/SettingsPageOnlineServices'
|
||||||
|
import SettingsPageRemotesOutputs from '@/pages/SettingsPageRemotesOutputs'
|
||||||
|
|
||||||
Vue.use(VueRouter)
|
Vue.use(VueRouter)
|
||||||
|
|
||||||
@ -218,6 +220,16 @@ export const router = new VueRouter({
|
|||||||
path: '/settings/webinterface',
|
path: '/settings/webinterface',
|
||||||
name: 'Settings Webinterface',
|
name: 'Settings Webinterface',
|
||||||
component: SettingsPageWebinterface
|
component: SettingsPageWebinterface
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/settings/online-services',
|
||||||
|
name: 'Settings Online Services',
|
||||||
|
component: SettingsPageOnlineServices
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/settings/remotes-outputs',
|
||||||
|
name: 'Settings Remotes Outputs',
|
||||||
|
component: SettingsPageRemotesOutputs
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
scrollBehavior (to, from, savedPosition) {
|
scrollBehavior (to, from, savedPosition) {
|
||||||
|
@ -39,7 +39,9 @@ export default new Vuex.Store({
|
|||||||
'count': 0,
|
'count': 0,
|
||||||
'items': [ ]
|
'items': [ ]
|
||||||
},
|
},
|
||||||
|
lastfm: {},
|
||||||
spotify: {},
|
spotify: {},
|
||||||
|
pairing: {},
|
||||||
|
|
||||||
spotify_new_releases: [],
|
spotify_new_releases: [],
|
||||||
spotify_featured_playlists: [],
|
spotify_featured_playlists: [],
|
||||||
@ -121,9 +123,15 @@ export default new Vuex.Store({
|
|||||||
[types.UPDATE_QUEUE] (state, queue) {
|
[types.UPDATE_QUEUE] (state, queue) {
|
||||||
state.queue = queue
|
state.queue = queue
|
||||||
},
|
},
|
||||||
|
[types.UPDATE_LASTFM] (state, lastfm) {
|
||||||
|
state.lastfm = lastfm
|
||||||
|
},
|
||||||
[types.UPDATE_SPOTIFY] (state, spotify) {
|
[types.UPDATE_SPOTIFY] (state, spotify) {
|
||||||
state.spotify = spotify
|
state.spotify = spotify
|
||||||
},
|
},
|
||||||
|
[types.UPDATE_PAIRING] (state, pairing) {
|
||||||
|
state.pairing = pairing
|
||||||
|
},
|
||||||
[types.SPOTIFY_NEW_RELEASES] (state, newReleases) {
|
[types.SPOTIFY_NEW_RELEASES] (state, newReleases) {
|
||||||
state.spotify_new_releases = newReleases
|
state.spotify_new_releases = newReleases
|
||||||
},
|
},
|
||||||
|
@ -7,7 +7,9 @@ export const UPDATE_LIBRARY_PODCASTS_COUNT = 'UPDATE_LIBRARY_PODCASTS_COUNT'
|
|||||||
export const UPDATE_OUTPUTS = 'UPDATE_OUTPUTS'
|
export const UPDATE_OUTPUTS = 'UPDATE_OUTPUTS'
|
||||||
export const UPDATE_PLAYER_STATUS = 'UPDATE_PLAYER_STATUS'
|
export const UPDATE_PLAYER_STATUS = 'UPDATE_PLAYER_STATUS'
|
||||||
export const UPDATE_QUEUE = 'UPDATE_QUEUE'
|
export const UPDATE_QUEUE = 'UPDATE_QUEUE'
|
||||||
|
export const UPDATE_LASTFM = 'UPDATE_LASTFM'
|
||||||
export const UPDATE_SPOTIFY = 'UPDATE_SPOTIFY'
|
export const UPDATE_SPOTIFY = 'UPDATE_SPOTIFY'
|
||||||
|
export const UPDATE_PAIRING = 'UPDATE_PAIRING'
|
||||||
|
|
||||||
export const SPOTIFY_NEW_RELEASES = 'SPOTIFY_NEW_RELEASES'
|
export const SPOTIFY_NEW_RELEASES = 'SPOTIFY_NEW_RELEASES'
|
||||||
export const SPOTIFY_FEATURED_PLAYLISTS = 'SPOTIFY_FEATURED_PLAYLISTS'
|
export const SPOTIFY_FEATURED_PLAYLISTS = 'SPOTIFY_FEATURED_PLAYLISTS'
|
||||||
|
@ -190,6 +190,10 @@ export default {
|
|||||||
return axios.put('/api/outputs/' + outputId, output)
|
return axios.put('/api/outputs/' + outputId, output)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
output_toggle (outputId) {
|
||||||
|
return axios.put('/api/outputs/' + outputId + '/toggle')
|
||||||
|
},
|
||||||
|
|
||||||
library_artists () {
|
library_artists () {
|
||||||
return axios.get('/api/library/artists?media_kind=music')
|
return axios.get('/api/library/artists?media_kind=music')
|
||||||
},
|
},
|
||||||
@ -316,6 +320,34 @@ export default {
|
|||||||
return axios.get('/api/spotify')
|
return axios.get('/api/spotify')
|
||||||
},
|
},
|
||||||
|
|
||||||
|
spotify_login (credentials) {
|
||||||
|
return axios.post('/api/spotify-login', credentials)
|
||||||
|
},
|
||||||
|
|
||||||
|
lastfm () {
|
||||||
|
return axios.get('/api/lastfm')
|
||||||
|
},
|
||||||
|
|
||||||
|
lastfm_login (credentials) {
|
||||||
|
return axios.post('/api/lastfm-login', credentials)
|
||||||
|
},
|
||||||
|
|
||||||
|
lastfm_logout (credentials) {
|
||||||
|
return axios.get('/api/lastfm-logout')
|
||||||
|
},
|
||||||
|
|
||||||
|
pairing () {
|
||||||
|
return axios.get('/api/pairing')
|
||||||
|
},
|
||||||
|
|
||||||
|
pairing_kickoff (pairingReq) {
|
||||||
|
return axios.post('/api/pairing', pairingReq)
|
||||||
|
},
|
||||||
|
|
||||||
|
verification_kickoff (verificationReq) {
|
||||||
|
return axios.post('/api/verification', verificationReq)
|
||||||
|
},
|
||||||
|
|
||||||
artwork_url_append_size_params (artworkUrl, maxwidth = 600, maxheight = 600) {
|
artwork_url_append_size_params (artworkUrl, maxwidth = 600, maxheight = 600) {
|
||||||
if (artworkUrl && artworkUrl.startsWith('/')) {
|
if (artworkUrl && artworkUrl.startsWith('/')) {
|
||||||
if (artworkUrl.includes('?')) {
|
if (artworkUrl.includes('?')) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user