mirror of
https://github.com/owntone/owntone-server.git
synced 2024-12-27 23:55:57 -05:00
commit
ccdcc0cbf9
File diff suppressed because one or more lines are too long
3979
web-src/package-lock.json
generated
3979
web-src/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -2,12 +2,13 @@
|
||||
"name": "owntone-web",
|
||||
"version": "2.0.0",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"serve": "vite",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview",
|
||||
"lint": "eslint --ext .js,.vue --ignore-path .gitignore --fix src",
|
||||
"format": "prettier . --write"
|
||||
"dev": "vite",
|
||||
"format": "prettier . --write",
|
||||
"i18n:report": "vue-cli-service i18n:report --src \"./src/**/*.?(js|vue)\" --locales \"./src/locales/**/*.json\"",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@aacassandra/vue3-progressbar": "^1.0.3",
|
||||
@ -23,6 +24,7 @@
|
||||
"spotify-web-api-js": "^1.5.2",
|
||||
"string-to-color": "^2.2.2",
|
||||
"vue": "^3.2.33",
|
||||
"vue-i18n": "^9.1.0",
|
||||
"vue-router": "^4.0.14",
|
||||
"vue-scrollto": "^2.20.0",
|
||||
"vue3-click-away": "^1.2.4",
|
||||
@ -31,12 +33,13 @@
|
||||
"vuex": "^4.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@intlify/vite-plugin-vue-i18n": "^3.4.0",
|
||||
"@vitejs/plugin-vue": "^2.3.1",
|
||||
"eslint": "^8.13.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-vue": "^8.6.0",
|
||||
"prettier": "2.6.2",
|
||||
"sass": "^1.50.0",
|
||||
"vite": "^2.9.5"
|
||||
"vite": "^2.9.8"
|
||||
}
|
||||
}
|
||||
|
@ -116,15 +116,6 @@ export default {
|
||||
|
||||
methods: {
|
||||
connect: function () {
|
||||
/*
|
||||
this.$store.dispatch('add_notification', {
|
||||
text: 'Connecting to OwnTone server',
|
||||
type: 'info',
|
||||
topic: 'connection',
|
||||
timeout: 2000
|
||||
})
|
||||
*/
|
||||
|
||||
webapi
|
||||
.config()
|
||||
.then(({ data }) => {
|
||||
@ -137,7 +128,7 @@ export default {
|
||||
})
|
||||
.catch(() => {
|
||||
this.$store.dispatch('add_notification', {
|
||||
text: 'Failed to connect to OwnTone server',
|
||||
text: this.$t('server.connection.failed'),
|
||||
type: 'danger',
|
||||
topic: 'connection'
|
||||
})
|
||||
@ -147,7 +138,7 @@ export default {
|
||||
open_ws: function () {
|
||||
if (this.$store.state.config.websocket_port <= 0) {
|
||||
this.$store.dispatch('add_notification', {
|
||||
text: 'Missing websocket port',
|
||||
text: this.$t('server.missing-port'),
|
||||
type: 'danger'
|
||||
})
|
||||
return
|
||||
@ -183,14 +174,6 @@ export default {
|
||||
})
|
||||
|
||||
socket.onopen = function () {
|
||||
/*
|
||||
vm.$store.dispatch('add_notification', {
|
||||
text: 'Connection to server established',
|
||||
type: 'primary',
|
||||
topic: 'connection',
|
||||
timeout: 2000
|
||||
})
|
||||
*/
|
||||
vm.reconnect_attempts = 0
|
||||
socket.send(
|
||||
JSON.stringify({
|
||||
@ -221,17 +204,6 @@ export default {
|
||||
socket.onclose = function () {
|
||||
// vm.$store.dispatch('add_notification', { text: 'Connection closed', type: 'danger', timeout: 2000 })
|
||||
}
|
||||
/*
|
||||
socket.onerror = function () {
|
||||
vm.reconnect_attempts++
|
||||
vm.$store.dispatch('add_notification', {
|
||||
text:
|
||||
'Connection lost. Reconnecting ... (' + vm.reconnect_attempts + ')',
|
||||
type: 'danger',
|
||||
topic: 'connection'
|
||||
})
|
||||
}
|
||||
*/
|
||||
|
||||
// When the app becomes active, force an update of all information, because we
|
||||
// may have missed notifications while the app was inactive.
|
||||
|
@ -11,23 +11,20 @@
|
||||
aria-controls="dropdown-menu"
|
||||
@click="is_active = !is_active"
|
||||
>
|
||||
<span>{{ modelValue }}</span>
|
||||
<span class="icon">
|
||||
<mdicon name="chevron-down" size="16" />
|
||||
</span>
|
||||
<span v-text="option.name" />
|
||||
<mdicon class="icon" name="chevron-down" size="16" />
|
||||
</button>
|
||||
</div>
|
||||
<div id="dropdown-menu" class="dropdown-menu" role="menu">
|
||||
<div class="dropdown-content">
|
||||
<a
|
||||
v-for="option in options"
|
||||
:key="option"
|
||||
v-for="o in options"
|
||||
:key="o.id"
|
||||
class="dropdown-item"
|
||||
:class="{ 'is-active': modelValue === option }"
|
||||
@click="select(option)"
|
||||
>
|
||||
{{ option }}
|
||||
</a>
|
||||
:class="{ 'is-active': modelValue === o.id }"
|
||||
@click="select(o)"
|
||||
v-text="o.name"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -36,8 +33,6 @@
|
||||
<script>
|
||||
export default {
|
||||
name: 'DropdownMenu',
|
||||
|
||||
// eslint-disable-next-line vue/prop-name-casing
|
||||
props: ['modelValue', 'options'],
|
||||
emits: ['update:modelValue'],
|
||||
|
||||
@ -47,6 +42,14 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
option: {
|
||||
get() {
|
||||
return this.options.find((option) => option.id === this.modelValue)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
onClickOutside(event) {
|
||||
this.is_active = false
|
||||
@ -54,7 +57,7 @@ export default {
|
||||
|
||||
select(option) {
|
||||
this.is_active = false
|
||||
this.$emit('update:modelValue', option)
|
||||
this.$emit('update:modelValue', option.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,8 +6,8 @@
|
||||
:key="char"
|
||||
class="button is-small"
|
||||
@click="nav(char)"
|
||||
>{{ char }}</a
|
||||
>
|
||||
v-text="char"
|
||||
/>
|
||||
</nav>
|
||||
</section>
|
||||
</template>
|
||||
@ -15,9 +15,7 @@
|
||||
<script>
|
||||
export default {
|
||||
name: 'IndexButtonList',
|
||||
|
||||
props: ['index'],
|
||||
|
||||
computed: {
|
||||
filtered_index() {
|
||||
if (!this.index) {
|
||||
@ -27,7 +25,6 @@ export default {
|
||||
return this.index.filter((c) => !specialChars.includes(c))
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
nav: function (id) {
|
||||
this.$router.push({ hash: '#index_' + id })
|
||||
|
@ -4,8 +4,8 @@
|
||||
<span
|
||||
:id="'index_' + album.groupKey"
|
||||
class="tag is-info is-light is-small has-text-weight-bold"
|
||||
>{{ album.groupKey }}</span
|
||||
>
|
||||
v-text="album.groupKey"
|
||||
/>
|
||||
</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">
|
||||
@ -24,25 +24,20 @@
|
||||
</div>
|
||||
<div class="media-content fd-has-action is-clipped">
|
||||
<div style="margin-top: 0.7rem">
|
||||
<h1 class="title is-6">
|
||||
{{ album.item.name }}
|
||||
</h1>
|
||||
<h1 class="title is-6" v-text="album.item.name" />
|
||||
<h2 class="subtitle is-7 has-text-grey">
|
||||
<b>{{ album.item.artist }}</b>
|
||||
<b v-text="album.item.artist" />
|
||||
</h2>
|
||||
<h2
|
||||
v-if="album.item.date_released && album.item.media_kind === 'music'"
|
||||
class="subtitle is-7 has-text-grey has-text-weight-normal"
|
||||
>
|
||||
{{ $filters.date(album.item.date_released) }}
|
||||
</h2>
|
||||
v-text="$filters.date(album.item.date_released)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="media-right" style="padding-top: 0.7rem">
|
||||
<a @click.prevent.stop="open_dialog(album.item)">
|
||||
<span class="icon has-text-dark"
|
||||
><mdicon name="dots-vertical" size="16"
|
||||
/></span>
|
||||
<mdicon class="icon has-text-dark" name="dots-vertical" size="16" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
@ -64,11 +59,10 @@
|
||||
@delete="remove_podcast"
|
||||
>
|
||||
<template #modal-content>
|
||||
<p>Permanently remove this podcast from your library?</p>
|
||||
<p v-text="$t('list.albums.info-1')" />
|
||||
<p class="is-size-7">
|
||||
(This will also remove the RSS playlist
|
||||
<b>{{ rss_playlist_to_remove.name }}</b
|
||||
>.)
|
||||
(<span v-text="$t('list.albums.info-2')" />
|
||||
<b v-text="rss_playlist_to_remove.name" />)
|
||||
</p>
|
||||
</template>
|
||||
</modal-dialog>
|
||||
@ -152,7 +146,7 @@ export default {
|
||||
const rssPlaylists = data.items.filter((pl) => pl.type === 'rss')
|
||||
if (rssPlaylists.length !== 1) {
|
||||
this.$store.dispatch('add_notification', {
|
||||
text: 'Podcast cannot be removed. Probably it was not added as an RSS playlist.',
|
||||
text: this.$t('list.albums.notification'),
|
||||
type: 'danger'
|
||||
})
|
||||
return
|
||||
|
@ -5,8 +5,8 @@
|
||||
<span
|
||||
:id="'index_' + artist.groupKey"
|
||||
class="tag is-info is-light is-small has-text-weight-bold"
|
||||
>{{ artist.groupKey }}</span
|
||||
>
|
||||
v-text="artist.groupKey"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
@ -15,15 +15,11 @@
|
||||
@click="open_artist(artist.item)"
|
||||
>
|
||||
<div class="media-content fd-has-action is-clipped">
|
||||
<h1 class="title is-6">
|
||||
{{ artist.item.name }}
|
||||
</h1>
|
||||
<h1 class="title is-6" v-text="artist.item.name" />
|
||||
</div>
|
||||
<div class="media-right">
|
||||
<a @click.prevent.stop="open_dialog(artist.item)">
|
||||
<span class="icon has-text-dark"
|
||||
><mdicon name="dots-vertical" size="16"
|
||||
/></span>
|
||||
<mdicon class="icon has-text-dark" name="dots-vertical" size="16" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -5,8 +5,8 @@
|
||||
<span
|
||||
:id="'index_' + composer.groupKey"
|
||||
class="tag is-info is-light is-small has-text-weight-bold"
|
||||
>{{ composer.groupKey }}</span
|
||||
>
|
||||
v-text="composer.groupKey"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
@ -15,15 +15,11 @@
|
||||
@click="open_composer(composer.item)"
|
||||
>
|
||||
<div class="media-content fd-has-action is-clipped">
|
||||
<h1 class="title is-6">
|
||||
{{ composer.item.name }}
|
||||
</h1>
|
||||
<h1 class="title is-6" v-text="composer.item.name" />
|
||||
</div>
|
||||
<div class="media-right">
|
||||
<a @click.prevent.stop="open_dialog(composer.item)">
|
||||
<span class="icon has-text-dark"
|
||||
><mdicon name="dots-vertical" size="16"
|
||||
/></span>
|
||||
<mdicon class="icon has-text-dark" name="dots-vertical" size="16" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
@ -44,7 +40,6 @@ import ModalDialogComposer from '@/components/ModalDialogComposer.vue'
|
||||
export default {
|
||||
name: 'ListComposers',
|
||||
components: { ModalDialogComposer },
|
||||
|
||||
props: ['composers', 'media_kind', 'hide_group_title'],
|
||||
|
||||
data() {
|
||||
|
@ -5,9 +5,7 @@
|
||||
@click="open_parent_directory()"
|
||||
>
|
||||
<figure class="media-left fd-has-action">
|
||||
<span class="icon">
|
||||
<mdicon name="subdirectory-arrow-left" size="16" />
|
||||
</span>
|
||||
<mdicon class="icon" name="subdirectory-arrow-left" size="16" />
|
||||
</figure>
|
||||
<div class="media-content fd-has-action is-clipped">
|
||||
<h1 class="title is-6">..</h1>
|
||||
@ -19,23 +17,18 @@
|
||||
<template v-for="directory in directories" :key="directory.path">
|
||||
<div class="media" @click="open_directory(directory)">
|
||||
<figure class="media-left fd-has-action">
|
||||
<span class="icon">
|
||||
<mdicon name="folder" size="16" />
|
||||
</span>
|
||||
<mdicon class="icon" name="folder" size="16" />
|
||||
</figure>
|
||||
<div class="media-content fd-has-action is-clipped">
|
||||
<h1 class="title is-6">
|
||||
{{ directory.path.substring(directory.path.lastIndexOf('/') + 1) }}
|
||||
</h1>
|
||||
<h2 class="subtitle is-7 has-text-grey-light">
|
||||
{{ directory.path }}
|
||||
</h2>
|
||||
<h1
|
||||
class="title is-6"
|
||||
v-text="directory.path.substring(directory.path.lastIndexOf('/') + 1)"
|
||||
/>
|
||||
<h2 class="subtitle is-7 has-text-grey-light" v-text="directory.path" />
|
||||
</div>
|
||||
<div class="media-right">
|
||||
<a @click.prevent.stop="open_dialog(directory)">
|
||||
<span class="icon has-text-dark"
|
||||
><mdicon name="dots-vertical" size="16"
|
||||
/></span>
|
||||
<mdicon class="icon has-text-dark" name="dots-vertical" size="16" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -5,21 +5,17 @@
|
||||
<span
|
||||
:id="'index_' + genre.groupKey"
|
||||
class="tag is-info is-light is-small has-text-weight-bold"
|
||||
>{{ genre.groupKey }}</span
|
||||
>
|
||||
v-text="genre.groupKey"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else-if="genre.isItem" class="media" @click="open_genre(genre.item)">
|
||||
<div class="media-content fd-has-action is-clipped">
|
||||
<h1 class="title is-6">
|
||||
{{ genre.item.name }}
|
||||
</h1>
|
||||
<h1 class="title is-6" v-text="genre.item.name" />
|
||||
</div>
|
||||
<div class="media-right">
|
||||
<a @click.prevent.stop="open_dialog(genre.item)">
|
||||
<span class="icon has-text-dark"
|
||||
><mdicon name="dots-vertical" size="16"
|
||||
/></span>
|
||||
<mdicon class="icon has-text-dark" name="dots-vertical" size="16" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,11 +1,12 @@
|
||||
<template>
|
||||
<div v-if="is_next || !show_only_next_items" class="media">
|
||||
<div v-if="edit_mode" class="media-left">
|
||||
<span class="icon has-text-grey fd-is-movable handle"
|
||||
><mdicon name="drag-horizontal" size="16"
|
||||
/></span>
|
||||
<mdicon
|
||||
class="icon has-text-grey fd-is-movable handle"
|
||||
name="drag-horizontal"
|
||||
size="16"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="media-content fd-has-action is-clipped" @click="play">
|
||||
<h1
|
||||
class="title is-6"
|
||||
@ -13,9 +14,8 @@
|
||||
'has-text-primary': item.id === state.item_id,
|
||||
'has-text-grey-light': !is_next
|
||||
}"
|
||||
>
|
||||
{{ item.title }}
|
||||
</h1>
|
||||
v-text="item.title"
|
||||
/>
|
||||
<h2
|
||||
class="subtitle is-7"
|
||||
:class="{
|
||||
@ -24,7 +24,7 @@
|
||||
'has-text-grey': is_next && item.id !== state.item_id
|
||||
}"
|
||||
>
|
||||
<b>{{ item.artist }}</b>
|
||||
<b v-text="item.artist" />
|
||||
</h2>
|
||||
<h2
|
||||
class="subtitle is-7"
|
||||
@ -33,9 +33,8 @@
|
||||
'has-text-grey-light': !is_next,
|
||||
'has-text-grey': is_next && item.id !== state.item_id
|
||||
}"
|
||||
>
|
||||
{{ item.album }}
|
||||
</h2>
|
||||
v-text="item.album"
|
||||
/>
|
||||
</div>
|
||||
<div class="media-right">
|
||||
<slot name="actions" />
|
||||
|
@ -7,20 +7,14 @@
|
||||
@click="open_playlist(playlist.item)"
|
||||
>
|
||||
<figure class="media-left fd-has-action">
|
||||
<span class="icon">
|
||||
<mdicon :name="icon_name(playlist.item)" size="16" />
|
||||
</span>
|
||||
<mdicon class="icon" :name="icon_name(playlist.item)" size="16" />
|
||||
</figure>
|
||||
<div class="media-content fd-has-action is-clipped">
|
||||
<h1 class="title is-6">
|
||||
{{ playlist.item.name }}
|
||||
</h1>
|
||||
<h1 class="title is-6" v-text="playlist.item.name" />
|
||||
</div>
|
||||
<div class="media-right">
|
||||
<a @click.prevent.stop="open_dialog(playlist.item)">
|
||||
<span class="icon has-text-dark"
|
||||
><mdicon name="dots-vertical" size="16"
|
||||
/></span>
|
||||
<mdicon class="icon has-text-dark" name="dots-vertical" size="16" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -8,9 +8,7 @@
|
||||
@click="play_track(index, track)"
|
||||
>
|
||||
<figure v-if="show_icon" class="media-left fd-has-action">
|
||||
<span class="icon">
|
||||
<mdicon name="file-outline" size="16" />
|
||||
</span>
|
||||
<mdicon class="icon" name="file-outline" size="16" />
|
||||
</figure>
|
||||
<div class="media-content fd-has-action is-clipped">
|
||||
<h1
|
||||
@ -19,15 +17,10 @@
|
||||
'has-text-grey':
|
||||
track.media_kind === 'podcast' && track.play_count > 0
|
||||
}"
|
||||
>
|
||||
{{ track.title }}
|
||||
</h1>
|
||||
<h2 class="subtitle is-7 has-text-grey">
|
||||
<b>{{ track.artist }}</b>
|
||||
</h2>
|
||||
<h2 class="subtitle is-7 has-text-grey">
|
||||
{{ track.album }}
|
||||
</h2>
|
||||
v-text="track.title"
|
||||
/>
|
||||
<h2 class="subtitle is-7 has-text-grey" v-text="track.artist" />
|
||||
<h2 class="subtitle is-7 has-text-grey" v-text="track.album" />
|
||||
<progress-bar
|
||||
v-if="show_progress"
|
||||
:max="track.length_ms"
|
||||
@ -36,13 +29,10 @@
|
||||
</div>
|
||||
<div class="media-right">
|
||||
<a @click.prevent.stop="open_dialog(track)">
|
||||
<span class="icon has-text-dark"
|
||||
><mdicon name="dots-vertical" size="16"
|
||||
/></span>
|
||||
<mdicon class="icon has-text-dark" name="dots-vertical" size="16" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<teleport to="#app">
|
||||
<modal-dialog-track
|
||||
:show="show_details_modal"
|
||||
|
@ -6,33 +6,32 @@
|
||||
<div class="modal-content fd-modal-card">
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<p v-if="title" class="title is-4">
|
||||
{{ title }}
|
||||
</p>
|
||||
<p v-if="title" class="title is-4" v-text="title" />
|
||||
<slot name="modal-content" />
|
||||
</div>
|
||||
<footer class="card-footer">
|
||||
<a class="card-footer-item has-text-dark" @click="$emit('close')">
|
||||
<span class="icon"><mdicon name="cancel" size="16" /></span>
|
||||
<span class="is-size-7">{{
|
||||
close_action ? close_action : 'Cancel'
|
||||
}}</span>
|
||||
<mdicon class="icon" name="cancel" size="16" />
|
||||
<span
|
||||
class="is-size-7"
|
||||
v-text="close_action ? close_action : t('dialog.cancel')"
|
||||
/>
|
||||
</a>
|
||||
<a
|
||||
v-if="delete_action"
|
||||
class="card-footer-item has-background-danger has-text-white has-text-weight-bold"
|
||||
@click="$emit('delete')"
|
||||
>
|
||||
<span class="icon"><mdicon name="delete" size="16" /></span>
|
||||
<span class="is-size-7">{{ delete_action }}</span>
|
||||
<mdicon class="icon" name="delete" size="16" />
|
||||
<span class="is-size-7" v-text="delete_action" />
|
||||
</a>
|
||||
<a
|
||||
v-if="ok_action"
|
||||
class="card-footer-item has-background-info has-text-white has-text-weight-bold"
|
||||
@click="$emit('ok')"
|
||||
>
|
||||
<span class="icon"><mdicon name="check" size="16" /></span>
|
||||
<span class="is-size-7">{{ ok_action }}</span>
|
||||
<mdicon class="icon" name="check" size="16" />
|
||||
<span class="is-size-7" v-text="ok_action" />
|
||||
</a>
|
||||
</footer>
|
||||
</div>
|
||||
|
@ -6,7 +6,7 @@
|
||||
<div class="modal-content fd-modal-card">
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<p class="title is-4">Add Podcast RSS feed URL</p>
|
||||
<p class="title is-4" v-text="$t('dialog.add.rss.title')" />
|
||||
<form @submit.prevent="add_stream">
|
||||
<div class="field">
|
||||
<p class="control is-expanded has-icons-left">
|
||||
@ -15,24 +15,22 @@
|
||||
v-model="url"
|
||||
class="input is-shadowless"
|
||||
type="text"
|
||||
placeholder="http://url-to-rss"
|
||||
:placeholder="$t('dialog.add.rss.placeholder')"
|
||||
:disabled="loading"
|
||||
/>
|
||||
<span class="icon is-left">
|
||||
<mdicon name="rss" size="16" />
|
||||
</span>
|
||||
</p>
|
||||
<p class="help">
|
||||
Adding a podcast includes creating an RSS playlist, that
|
||||
will allow OwnTone to manage the podcast subscription.
|
||||
<mdicon class="icon is-left" name="rss" size="16" />
|
||||
</p>
|
||||
<p class="help" v-text="$t('dialog.add.rss.help')" />
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<footer v-if="loading" class="card-footer">
|
||||
<a class="card-footer-item button is-loading">
|
||||
<span class="icon"><mdicon name="web" size="16" /></span>
|
||||
<span class="is-size-7">Processing ...</span>
|
||||
<mdicon class="icon" name="web" size="16" />
|
||||
<span
|
||||
class="is-size-7"
|
||||
v-text="$t('dialog.add.rss.processing')"
|
||||
/>
|
||||
</a>
|
||||
</footer>
|
||||
<footer v-else class="card-footer">
|
||||
@ -40,17 +38,15 @@
|
||||
class="card-footer-item has-text-danger"
|
||||
@click="$emit('close')"
|
||||
>
|
||||
<span class="icon"><mdicon name="cancel" size="16" /></span>
|
||||
<span class="is-size-7">Cancel</span>
|
||||
<mdicon class="icon" name="cancel" size="16" />
|
||||
<span class="is-size-7" v-text="$t('dialog.add.rss.cancel')" />
|
||||
</a>
|
||||
<a
|
||||
class="card-footer-item has-background-info has-text-white has-text-weight-bold"
|
||||
@click="add_stream"
|
||||
>
|
||||
<span class="icon"
|
||||
><mdicon name="playlist-plus" size="16"
|
||||
/></span>
|
||||
<span class="is-size-7">Add</span>
|
||||
<mdicon class="icon" name="playlist-plus" size="16" />
|
||||
<span class="is-size-7" v-text="$t('dialog.add.rss.add')" />
|
||||
</a>
|
||||
</footer>
|
||||
</div>
|
||||
|
@ -6,7 +6,7 @@
|
||||
<div class="modal-content fd-modal-card">
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<p class="title is-4">Add stream URL</p>
|
||||
<p class="title is-4" v-text="$t('dialog.add.stream.title')" />
|
||||
<form class="fd-has-margin-bottom" @submit.prevent="play">
|
||||
<div class="field">
|
||||
<p class="control is-expanded has-icons-left">
|
||||
@ -15,20 +15,21 @@
|
||||
v-model="url"
|
||||
class="input is-shadowless"
|
||||
type="text"
|
||||
placeholder="http://url-to-stream"
|
||||
:placeholder="$t('dialog.add.stream.placeholder')"
|
||||
:disabled="loading"
|
||||
/>
|
||||
<span class="icon is-left">
|
||||
<mdicon name="web" size="16" />
|
||||
</span>
|
||||
<mdicon class="icon is-left" name="web" size="16" />
|
||||
</p>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<footer v-if="loading" class="card-footer">
|
||||
<a class="card-footer-item has-text-dark">
|
||||
<span class="icon"><mdicon name="web" size="16" /></span>
|
||||
<span class="is-size-7">Loading ...</span>
|
||||
<mdicon class="icon" name="web" size="16" />
|
||||
<span
|
||||
class="is-size-7"
|
||||
v-text="$t('dialog.add.stream.loading')"
|
||||
/>
|
||||
</a>
|
||||
</footer>
|
||||
<footer v-else class="card-footer">
|
||||
@ -36,21 +37,22 @@
|
||||
class="card-footer-item has-text-danger"
|
||||
@click="$emit('close')"
|
||||
>
|
||||
<span class="icon"><mdicon name="cancel" size="16" /></span>
|
||||
<span class="is-size-7">Cancel</span>
|
||||
<mdicon class="icon" name="cancel" size="16" />
|
||||
<span
|
||||
class="is-size-7"
|
||||
v-text="$t('dialog.add.stream.cancel')"
|
||||
/>
|
||||
</a>
|
||||
<a class="card-footer-item has-text-dark" @click="add_stream">
|
||||
<span class="icon"
|
||||
><mdicon name="playlist-plus" size="16"
|
||||
/></span>
|
||||
<span class="is-size-7">Add</span>
|
||||
<mdicon class="icon" name="playlist-plus" size="16" />
|
||||
<span class="is-size-7" v-text="$t('dialog.add.stream.add')" />
|
||||
</a>
|
||||
<a
|
||||
class="card-footer-item has-background-info has-text-white has-text-weight-bold"
|
||||
@click="play"
|
||||
>
|
||||
<span class="icon"><mdicon name="play" size="16" /></span>
|
||||
<span class="is-size-7">Play</span>
|
||||
<mdicon class="icon" name="play" size="16" />
|
||||
<span class="is-size-7" v-text="$t('dialog.add.stream.play')" />
|
||||
</a>
|
||||
</footer>
|
||||
</div>
|
||||
|
@ -13,75 +13,91 @@
|
||||
class="image is-square fd-has-margin-bottom fd-has-shadow"
|
||||
/>
|
||||
<p class="title is-4">
|
||||
<a class="has-text-link" @click="open_album">{{
|
||||
album.name
|
||||
}}</a>
|
||||
<a
|
||||
class="has-text-link"
|
||||
@click="open_album"
|
||||
v-text="album.name"
|
||||
/>
|
||||
</p>
|
||||
<div v-if="media_kind_resolved === 'podcast'" class="buttons">
|
||||
<a class="button is-small" @click="mark_played"
|
||||
>Mark as played</a
|
||||
>
|
||||
<a class="button is-small" @click="$emit('remove-podcast')"
|
||||
>Remove podcast</a
|
||||
>
|
||||
<a
|
||||
class="button is-small"
|
||||
@click="mark_played"
|
||||
v-text="$t('dialog.album.mark-as-played')"
|
||||
/>
|
||||
<a
|
||||
class="button is-small"
|
||||
@click="$emit('remove-podcast')"
|
||||
v-text="$t('dialog.album.remove-podcast')"
|
||||
/>
|
||||
</div>
|
||||
<div class="content is-small">
|
||||
<p v-if="album.artist">
|
||||
<span class="heading">Album artist</span>
|
||||
<a class="title is-6 has-text-link" @click="open_artist">{{
|
||||
album.artist
|
||||
}}</a>
|
||||
<span class="heading" v-text="$t('dialog.album.artist')" />
|
||||
<a
|
||||
class="title is-6 has-text-link"
|
||||
@click="open_artist"
|
||||
v-text="album.artist"
|
||||
/>
|
||||
</p>
|
||||
<p v-if="album.date_released">
|
||||
<span class="heading">Release date</span>
|
||||
<span class="title is-6">{{
|
||||
$filters.date(album.date_released)
|
||||
}}</span>
|
||||
<span
|
||||
class="heading"
|
||||
v-text="$t('dialog.album.release-date')"
|
||||
/>
|
||||
<span
|
||||
class="title is-6"
|
||||
v-text="$filters.date(album.date_released)"
|
||||
/>
|
||||
</p>
|
||||
<p v-else-if="album.year > 0">
|
||||
<span class="heading">Year</span>
|
||||
<span class="title is-6">{{ album.year }}</span>
|
||||
<span class="heading" v-text="$t('dialog.album.year')" />
|
||||
<span class="title is-6" v-text="album.year" />
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading">Tracks</span>
|
||||
<span class="title is-6">{{ album.track_count }}</span>
|
||||
<span class="heading" v-text="$t('dialog.album.tracks')" />
|
||||
<span class="title is-6" v-text="album.track_count" />
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading">Length</span>
|
||||
<span class="title is-6">{{
|
||||
$filters.durationInHours(album.length_ms)
|
||||
}}</span>
|
||||
<span class="heading" v-text="$t('dialog.album.duration')" />
|
||||
<span
|
||||
class="title is-6"
|
||||
v-text="$filters.durationInHours(album.length_ms)"
|
||||
/>
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading">Type</span>
|
||||
<span class="title is-6"
|
||||
>{{ album.media_kind }} - {{ album.data_kind }}</span
|
||||
>
|
||||
<span class="heading" v-text="$t('dialog.album.type')" />
|
||||
<span
|
||||
class="title is-6"
|
||||
v-text="
|
||||
[
|
||||
t('media.kind.' + album.media_kind),
|
||||
t('data.kind.' + album.data_kind)
|
||||
].join(' - ')
|
||||
"
|
||||
/>
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading">Added at</span>
|
||||
<span class="title is-6">{{
|
||||
$filters.datetime(album.time_added)
|
||||
}}</span>
|
||||
<span class="heading" v-text="$t('dialog.album.added-on')" />
|
||||
<span
|
||||
class="title is-6"
|
||||
v-text="$filters.datetime(album.time_added)"
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<footer class="card-footer">
|
||||
<a class="card-footer-item has-text-dark" @click="queue_add">
|
||||
<span class="icon"
|
||||
><mdicon name="playlist-plus" size="16"
|
||||
/></span>
|
||||
<span class="is-size-7">Add</span>
|
||||
<mdicon class="icon" name="playlist-plus" size="16" />
|
||||
<span class="is-size-7" v-text="$t('dialog.album.add')" />
|
||||
</a>
|
||||
<a class="card-footer-item has-text-dark" @click="queue_add_next">
|
||||
<span class="icon"
|
||||
><mdicon name="playlist-play" size="16"
|
||||
/></span>
|
||||
<span class="is-size-7">Add Next</span>
|
||||
<mdicon class="icon" name="playlist-play" size="16" />
|
||||
<span class="is-size-7" v-text="$t('dialog.album.add-next')" />
|
||||
</a>
|
||||
<a class="card-footer-item has-text-dark" @click="play">
|
||||
<span class="icon"><mdicon name="play" size="16" /></span>
|
||||
<span class="is-size-7">Play</span>
|
||||
<mdicon class="icon" name="play" size="16" />
|
||||
<span class="is-size-7" v-text="$t('dialog.album.play')" />
|
||||
</a>
|
||||
</footer>
|
||||
</div>
|
||||
|
@ -7,47 +7,49 @@
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<p class="title is-4">
|
||||
<a class="has-text-link" @click="open_artist">{{
|
||||
artist.name
|
||||
}}</a>
|
||||
<a
|
||||
class="has-text-link"
|
||||
@click="open_artist"
|
||||
v-text="artist.name"
|
||||
/>
|
||||
</p>
|
||||
<div class="content is-small">
|
||||
<p>
|
||||
<span class="heading">Albums</span>
|
||||
<span class="title is-6">{{ artist.album_count }}</span>
|
||||
<span class="heading" v-text="$t('dialog.artist.albums')" />
|
||||
<span class="title is-6" v-text="artist.album_count" />
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading">Tracks</span>
|
||||
<span class="title is-6">{{ artist.track_count }}</span>
|
||||
<span class="heading" v-text="$t('dialog.artist.tracks')" />
|
||||
<span class="title is-6" v-text="artist.track_count" />
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading">Type</span>
|
||||
<span class="title is-6">{{ artist.data_kind }}</span>
|
||||
<span class="heading" v-text="$t('dialog.artist.type')" />
|
||||
<span
|
||||
class="title is-6"
|
||||
v-text="$t('data.kind.' + artist.data_kind)"
|
||||
/>
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading">Added at</span>
|
||||
<span class="title is-6">{{
|
||||
$filters.datetime(artist.time_added)
|
||||
}}</span>
|
||||
<span class="heading" v-text="$t('dialog.artist.added-on')" />
|
||||
<span
|
||||
class="title is-6"
|
||||
v-text="$filters.datetime(artist.time_added)"
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<footer class="card-footer">
|
||||
<a class="card-footer-item has-text-dark" @click="queue_add">
|
||||
<span class="icon"
|
||||
><mdicon name="playlist-plus" size="16"
|
||||
/></span>
|
||||
<span class="is-size-7">Add</span>
|
||||
<mdicon class="icon" name="playlist-plus" size="16" />
|
||||
<span class="is-size-7" v-text="$t('dialog.artist.add')" />
|
||||
</a>
|
||||
<a class="card-footer-item has-text-dark" @click="queue_add_next">
|
||||
<span class="icon"
|
||||
><mdicon name="playlist-play" size="16"
|
||||
/></span>
|
||||
<span class="is-size-7">Add Next</span>
|
||||
<mdicon class="icon" name="playlist-play" size="16" />
|
||||
<span class="is-size-7" v-text="$t('dialog.artist.add-next')" />
|
||||
</a>
|
||||
<a class="card-footer-item has-text-dark" @click="play">
|
||||
<span class="icon"><mdicon name="play" size="16" /></span>
|
||||
<span class="is-size-7">Play</span>
|
||||
<mdicon class="icon" name="play" size="16" />
|
||||
<span class="is-size-7" v-text="$t('dialog.artist.play')" />
|
||||
</a>
|
||||
</footer>
|
||||
</div>
|
||||
|
@ -7,45 +7,51 @@
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<p class="title is-4">
|
||||
<a class="has-text-link" @click="open_albums">{{
|
||||
composer.name
|
||||
}}</a>
|
||||
<a
|
||||
class="has-text-link"
|
||||
@click="open_albums"
|
||||
v-text="composer.name"
|
||||
/>
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading">Albums</span>
|
||||
<a class="has-text-link is-6" @click="open_albums">{{
|
||||
composer.album_count
|
||||
}}</a>
|
||||
<span class="heading" v-text="$t('dialog.composer.albums')" />
|
||||
<a
|
||||
class="has-text-link is-6"
|
||||
@click="open_albums"
|
||||
v-text="composer.album_count"
|
||||
/>
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading">Tracks</span>
|
||||
<a class="has-text-link is-6" @click="open_tracks">{{
|
||||
composer.track_count
|
||||
}}</a>
|
||||
<span class="heading" v-text="$t('dialog.composer.tracks')" />
|
||||
<a
|
||||
class="has-text-link is-6"
|
||||
@click="open_tracks"
|
||||
v-text="composer.track_count"
|
||||
/>
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading">Length</span>
|
||||
<span class="title is-6">{{
|
||||
$filters.durationInHours(composer.length_ms)
|
||||
}}</span>
|
||||
<span class="heading" v-text="$t('dialog.composer.duration')" />
|
||||
<span
|
||||
class="title is-6"
|
||||
v-text="$filters.durationInHours(composer.length_ms)"
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
<footer class="card-footer">
|
||||
<a class="card-footer-item has-text-dark" @click="queue_add">
|
||||
<span class="icon"
|
||||
><mdicon name="playlist-plus" size="16"
|
||||
/></span>
|
||||
<span class="is-size-7">Add</span>
|
||||
<mdicon class="icon" name="playlist-plus" size="16" />
|
||||
<span class="is-size-7" v-text="$t('dialog.composer.add')" />
|
||||
</a>
|
||||
<a class="card-footer-item has-text-dark" @click="queue_add_next">
|
||||
<span class="icon"
|
||||
><mdicon name="playlist-play" size="16"
|
||||
/></span>
|
||||
<span class="is-size-7">Add Next</span>
|
||||
<mdicon class="icon" name="playlist-play" size="16" />
|
||||
<span
|
||||
class="is-size-7"
|
||||
v-text="$t('dialog.composer.add-next')"
|
||||
/>
|
||||
</a>
|
||||
<a class="card-footer-item has-text-dark" @click="play">
|
||||
<span class="icon"><mdicon name="play" size="16" /></span>
|
||||
<span class="is-size-7">Play</span>
|
||||
<mdicon class="icon" name="play" size="16" />
|
||||
<span class="is-size-7" v-text="$t('dialog.composer.play')" />
|
||||
</a>
|
||||
</footer>
|
||||
</div>
|
||||
|
@ -6,26 +6,23 @@
|
||||
<div class="modal-content fd-modal-card">
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<p class="title is-4">
|
||||
{{ directory.path }}
|
||||
</p>
|
||||
<p class="title is-4" v-text="directory.path" />
|
||||
</div>
|
||||
<footer class="card-footer">
|
||||
<a class="card-footer-item has-text-dark" @click="queue_add">
|
||||
<span class="icon"
|
||||
><mdicon name="playlist-plus" size="16"
|
||||
/></span>
|
||||
<span class="is-size-7">Add</span>
|
||||
<mdicon class="icon" name="playlist-plus" size="16" />
|
||||
<span class="is-size-7" v-text="$t('dialog.directory.add')" />
|
||||
</a>
|
||||
<a class="card-footer-item has-text-dark" @click="queue_add_next">
|
||||
<span class="icon"
|
||||
><mdicon name="playlist-play" size="16"
|
||||
/></span>
|
||||
<span class="is-size-7">Add Next</span>
|
||||
<mdicon class="icon" name="playlist-play" size="16" />
|
||||
<span
|
||||
class="is-size-7"
|
||||
v-text="$t('dialog.directory.add-next')"
|
||||
/>
|
||||
</a>
|
||||
<a class="card-footer-item has-text-dark" @click="play">
|
||||
<span class="icon"><mdicon name="play" size="16" /></span>
|
||||
<span class="is-size-7">Play</span>
|
||||
<mdicon class="icon" name="play" size="16" />
|
||||
<span class="is-size-7" v-text="$t('dialog.directory.play')" />
|
||||
</a>
|
||||
</footer>
|
||||
</div>
|
||||
|
@ -7,43 +7,42 @@
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<p class="title is-4">
|
||||
<a class="has-text-link" @click="open_genre">{{
|
||||
genre.name
|
||||
}}</a>
|
||||
<a
|
||||
class="has-text-link"
|
||||
@click="open_genre"
|
||||
v-text="genre.name"
|
||||
/>
|
||||
</p>
|
||||
<div class="content is-small">
|
||||
<p>
|
||||
<span class="heading">Albums</span>
|
||||
<span class="title is-6">{{ genre.album_count }}</span>
|
||||
<span class="heading" v-text="$t('dialog.genre.albums')" />
|
||||
<span class="title is-6" v-text="genre.album_count" />
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading">Tracks</span>
|
||||
<span class="title is-6">{{ genre.track_count }}</span>
|
||||
<span class="heading" v-text="$t('dialog.genre.tracks')" />
|
||||
<span class="title is-6" v-text="genre.track_count" />
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading">Length</span>
|
||||
<span class="title is-6">{{
|
||||
$filters.durationInHours(genre.length_ms)
|
||||
}}</span>
|
||||
<span class="heading" v-text="$t('dialog.genre.duration')" />
|
||||
<span
|
||||
class="title is-6"
|
||||
v-text="$filters.durationInHours(genre.length_ms)"
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<footer class="card-footer">
|
||||
<a class="card-footer-item has-text-dark" @click="queue_add">
|
||||
<span class="icon"
|
||||
><mdicon name="playlist-plus" size="16"
|
||||
/></span>
|
||||
<span class="is-size-7">Add</span>
|
||||
<mdicon class="icon" name="playlist-plus" size="16" />
|
||||
<span class="is-size-7" v-text="$t('dialog.genre.add')" />
|
||||
</a>
|
||||
<a class="card-footer-item has-text-dark" @click="queue_add_next">
|
||||
<span class="icon"
|
||||
><mdicon name="playlist-play" size="16"
|
||||
/></span>
|
||||
<span class="is-size-7">Add Next</span>
|
||||
<mdicon class="icon" name="playlist-play" size="16" />
|
||||
<span class="is-size-7" v-text="$t('dialog.genre.add-next')" />
|
||||
</a>
|
||||
<a class="card-footer-item has-text-dark" @click="play">
|
||||
<span class="icon"><mdicon name="play" size="16" /></span>
|
||||
<span class="is-size-7">Play</span>
|
||||
<mdicon class="icon" name="play" size="16" />
|
||||
<span class="is-size-7" v-text="$t('dialog.genre.play')" />
|
||||
</a>
|
||||
</footer>
|
||||
</div>
|
||||
|
@ -7,41 +7,45 @@
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<p class="title is-4">
|
||||
<a class="has-text-link" @click="open_playlist">{{
|
||||
playlist.name
|
||||
}}</a>
|
||||
<a
|
||||
class="has-text-link"
|
||||
@click="open_playlist"
|
||||
v-text="playlist.name"
|
||||
/>
|
||||
</p>
|
||||
<div class="content is-small">
|
||||
<p>
|
||||
<span class="heading">Path</span>
|
||||
<span class="title is-6">{{ playlist.path }}</span>
|
||||
<span class="title is-6" v-text="playlist.path" />
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading">Type</span>
|
||||
<span class="title is-6">{{ playlist.type }}</span>
|
||||
<span class="heading" v-text="$t('dialog.playlist.type')" />
|
||||
<span class="title is-6" v-text="playlist.type" />
|
||||
</p>
|
||||
<p v-if="!playlist.folder">
|
||||
<span class="heading">Track count</span>
|
||||
<span class="title is-6">{{ playlist.item_count }}</span>
|
||||
<span
|
||||
class="heading"
|
||||
v-text="$t('dialog.playlist.track-count')"
|
||||
/>
|
||||
<span class="title is-6" v-text="playlist.item_count" />
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<footer v-if="!playlist.folder" class="card-footer">
|
||||
<a class="card-footer-item has-text-dark" @click="queue_add">
|
||||
<span class="icon"
|
||||
><mdicon name="playlist-plus" size="16"
|
||||
/></span>
|
||||
<span class="is-size-7">Add</span>
|
||||
<mdicon class="icon" name="playlist-plus" size="16" />
|
||||
<span class="is-size-7" v-text="$t('dialog.playlist.add')" />
|
||||
</a>
|
||||
<a class="card-footer-item has-text-dark" @click="queue_add_next">
|
||||
<span class="icon"
|
||||
><mdicon name="playlist-play" size="16"
|
||||
/></span>
|
||||
<span class="is-size-7">Add Next</span>
|
||||
<mdicon class="icon" name="playlist-play" size="16" />
|
||||
<span
|
||||
class="is-size-7"
|
||||
v-text="$t('dialog.playlist.add-next')"
|
||||
/>
|
||||
</a>
|
||||
<a class="card-footer-item has-text-dark" @click="play">
|
||||
<span class="icon"><mdicon name="play" size="16" /></span>
|
||||
<span class="is-size-7">Play</span>
|
||||
<mdicon class="icon" name="play" size="16" />
|
||||
<span class="is-size-7" v-text="$t('dialog.playlist.play')" />
|
||||
</a>
|
||||
</footer>
|
||||
</div>
|
||||
|
@ -6,7 +6,7 @@
|
||||
<div class="modal-content fd-modal-card">
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<p class="title is-4">Save queue to playlist</p>
|
||||
<p class="title is-4" v-text="$t('dialog.playlist.save.title')" />
|
||||
<form class="fd-has-margin-bottom" @submit.prevent="save">
|
||||
<div class="field">
|
||||
<p class="control is-expanded has-icons-left">
|
||||
@ -18,17 +18,18 @@
|
||||
placeholder="Playlist name"
|
||||
:disabled="loading"
|
||||
/>
|
||||
<span class="icon is-left">
|
||||
<mdicon name="file-music" size="16" />
|
||||
</span>
|
||||
<mdicon class="icon is-left" name="file-music" size="16" />
|
||||
</p>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<footer v-if="loading" class="card-footer">
|
||||
<a class="card-footer-item has-text-dark">
|
||||
<span class="icon"><mdicon name="web" size="16" /></span>
|
||||
<span class="is-size-7">Saving ...</span>
|
||||
<mdicon class="icon" name="web" size="16" />
|
||||
<span
|
||||
class="is-size-7"
|
||||
v-text="$t('dialog.playlist.save.saving')"
|
||||
/>
|
||||
</a>
|
||||
</footer>
|
||||
<footer v-else class="card-footer">
|
||||
@ -36,17 +37,21 @@
|
||||
class="card-footer-item has-text-danger"
|
||||
@click="$emit('close')"
|
||||
>
|
||||
<span class="icon"><mdicon name="cancel" size="16" /></span>
|
||||
<span class="is-size-7">Cancel</span>
|
||||
<mdicon class="icon" name="cancel" size="16" />
|
||||
<span
|
||||
class="is-size-7"
|
||||
v-text="$t('dialog.playlist.save.cancel')"
|
||||
/>
|
||||
</a>
|
||||
<a
|
||||
class="card-footer-item has-background-info has-text-white has-text-weight-bold"
|
||||
@click="save"
|
||||
>
|
||||
<span class="icon"
|
||||
><mdicon name="content-save" size="16"
|
||||
/></span>
|
||||
<span class="is-size-7">Save</span>
|
||||
<mdicon class="icon" name="content-save" size="16" />
|
||||
<span
|
||||
class="is-size-7"
|
||||
v-text="$t('dialog.playlist.save.save')"
|
||||
/>
|
||||
</a>
|
||||
</footer>
|
||||
</div>
|
||||
|
@ -6,98 +6,146 @@
|
||||
<div class="modal-content fd-modal-card">
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<p class="title is-4">
|
||||
{{ item.title }}
|
||||
</p>
|
||||
<p class="subtitle">
|
||||
{{ item.artist }}
|
||||
</p>
|
||||
<p class="title is-4" v-text="item.title" />
|
||||
<p class="subtitle" v-text="item.artist" />
|
||||
<div class="content is-small">
|
||||
<p>
|
||||
<span class="heading">Album</span>
|
||||
<span
|
||||
class="heading"
|
||||
v-text="$t('dialog.queue-item.album')"
|
||||
/>
|
||||
<a
|
||||
v-if="item.album_id"
|
||||
class="title is-6 has-text-link"
|
||||
@click="open_album"
|
||||
>{{ item.album }}</a
|
||||
>
|
||||
<span v-else class="title is-6">{{ item.album }}</span>
|
||||
v-text="item.album"
|
||||
/>
|
||||
<span v-else class="title is-6" v-text="item.album" />
|
||||
</p>
|
||||
<p v-if="item.album_artist">
|
||||
<span class="heading">Album artist</span>
|
||||
<span
|
||||
class="heading"
|
||||
v-text="$t('dialog.queue-item.album-artist')"
|
||||
/>
|
||||
<a
|
||||
v-if="item.album_artist_id"
|
||||
class="title is-6 has-text-link"
|
||||
@click="open_album_artist"
|
||||
>{{ item.album_artist }}</a
|
||||
>
|
||||
<span v-else class="title is-6">{{ item.album_artist }}</span>
|
||||
v-text="item.album_artist"
|
||||
/>
|
||||
<span v-else class="title is-6" v-text="item.album_artist" />
|
||||
</p>
|
||||
<p v-if="item.composer">
|
||||
<span class="heading">Composer</span>
|
||||
<span class="title is-6">{{ item.composer }}</span>
|
||||
<span
|
||||
class="heading"
|
||||
v-text="$t('dialog.queue-item.composer')"
|
||||
/>
|
||||
<span class="title is-6" v-text="item.composer" />
|
||||
</p>
|
||||
<p v-if="item.year > 0">
|
||||
<span class="heading">Year</span>
|
||||
<span class="title is-6">{{ item.year }}</span>
|
||||
<span class="heading" v-text="$t('dialog.queue-item.year')" />
|
||||
<span class="title is-6" v-text="item.year" />
|
||||
</p>
|
||||
<p v-if="item.genre">
|
||||
<span class="heading">Genre</span>
|
||||
<a class="title is-6 has-text-link" @click="open_genre">{{
|
||||
item.genre
|
||||
}}</a>
|
||||
<span
|
||||
class="heading"
|
||||
v-text="$t('dialog.queue-item.genre')"
|
||||
/>
|
||||
<a
|
||||
class="title is-6 has-text-link"
|
||||
@click="open_genre"
|
||||
v-text="item.genre"
|
||||
/>
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading">Track / Disc</span>
|
||||
<span class="title is-6"
|
||||
>{{ item.track_number }} / {{ item.disc_number }}</span
|
||||
>
|
||||
<span
|
||||
class="heading"
|
||||
v-text="$t('dialog.queue-item.position')"
|
||||
/>
|
||||
<span
|
||||
class="title is-6"
|
||||
v-text="[item.disc_number, item.track_number].join(' / ')"
|
||||
/>
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading">Length</span>
|
||||
<span class="title is-6">{{
|
||||
$filters.durationInHours(item.length_ms)
|
||||
}}</span>
|
||||
<span
|
||||
class="heading"
|
||||
v-text="$t('dialog.queue-item.duration')"
|
||||
/>
|
||||
<span
|
||||
class="title is-6"
|
||||
v-text="$filters.durationInHours(item.length_ms)"
|
||||
/>
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading">Path</span>
|
||||
<span class="title is-6">{{ item.path }}</span>
|
||||
<span class="heading" v-text="$t('dialog.queue-item.path')" />
|
||||
<span class="title is-6" v-text="item.path" />
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading">Type</span>
|
||||
<span class="title is-6"
|
||||
>{{ item.media_kind }} - {{ item.data_kind }}
|
||||
<span class="heading" v-text="$t('dialog.queue-item.type')" />
|
||||
<span class="title is-6">
|
||||
<span
|
||||
v-text="[item.media_kind, item.data_kind].join(' - ')"
|
||||
/>
|
||||
<span
|
||||
v-if="item.data_kind === 'spotify'"
|
||||
class="has-text-weight-normal"
|
||||
>(<a @click="open_spotify_artist">artist</a>,
|
||||
<a @click="open_spotify_album">album</a>)</span
|
||||
></span
|
||||
>
|
||||
>
|
||||
(<a
|
||||
@click="open_spotify_artist"
|
||||
v-text="$t('dialog.queue-item.spotify-artist')"
|
||||
/>,
|
||||
<a
|
||||
@click="open_spotify_album"
|
||||
v-text="$t('dialog.queue-item.spotify-album')"
|
||||
/>)
|
||||
</span>
|
||||
</span>
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading">Quality</span>
|
||||
<span
|
||||
class="heading"
|
||||
v-text="$t('dialog.queue-item.quality')"
|
||||
/>
|
||||
<span class="title is-6">
|
||||
{{ item.type }}
|
||||
<span v-if="item.samplerate">
|
||||
| {{ item.samplerate }} Hz</span
|
||||
>
|
||||
<span v-if="item.channels">
|
||||
| {{ $filters.channels(item.channels) }}</span
|
||||
>
|
||||
<span v-if="item.bitrate"> | {{ item.bitrate }} Kb/s</span>
|
||||
<span v-text="item.type" />
|
||||
<span
|
||||
v-if="item.samplerate"
|
||||
v-text="
|
||||
$t('dialog.queue-item.samplerate', {
|
||||
rate: item.samplerate
|
||||
})
|
||||
"
|
||||
/>
|
||||
<span
|
||||
v-if="item.channels"
|
||||
v-text="
|
||||
$t('dialog.queue-item.channels', {
|
||||
channels: $filters.channels(item.channels)
|
||||
})
|
||||
"
|
||||
/>
|
||||
<span
|
||||
v-if="item.bitrate"
|
||||
v-text="
|
||||
$t('dialog.queue-item.bitrate', { rate: item.bitrate })
|
||||
"
|
||||
/>
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<footer class="card-footer">
|
||||
<a class="card-footer-item has-text-dark" @click="remove">
|
||||
<span class="icon"><mdicon name="delete" size="16" /></span>
|
||||
<span class="is-size-7">Remove</span>
|
||||
<mdicon class="icon" name="delete" size="16" />
|
||||
<span
|
||||
class="is-size-7"
|
||||
v-text="$t('dialog.queue-item.remove')"
|
||||
/>
|
||||
</a>
|
||||
<a class="card-footer-item has-text-dark" @click="play">
|
||||
<span class="icon"><mdicon name="play" size="16" /></span>
|
||||
<span class="is-size-7">Play</span>
|
||||
<mdicon class="icon" name="play" size="16" />
|
||||
<span class="is-size-7" v-text="$t('dialog.queue-item.play')" />
|
||||
</a>
|
||||
</footer>
|
||||
</div>
|
||||
|
@ -6,11 +6,12 @@
|
||||
<div class="modal-content fd-modal-card">
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<p class="title is-4">Remote pairing request</p>
|
||||
<p
|
||||
class="title is-4"
|
||||
v-text="$t('dialog.remote-pairing.title')"
|
||||
/>
|
||||
<form @submit.prevent="kickoff_pairing">
|
||||
<label class="label">
|
||||
{{ pairing.remote }}
|
||||
</label>
|
||||
<label class="label" v-text="pairing.remote" />
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
<input
|
||||
@ -29,15 +30,21 @@
|
||||
class="card-footer-item has-text-danger"
|
||||
@click="$emit('close')"
|
||||
>
|
||||
<span class="icon"><mdicon name="cancel" size="16" /></span>
|
||||
<span class="is-size-7">Cancel</span>
|
||||
<mdicon class="icon" name="cancel" size="16" />
|
||||
<span
|
||||
class="is-size-7"
|
||||
v-text="$t('dialog.remote-pairing.cancel')"
|
||||
/>
|
||||
</a>
|
||||
<a
|
||||
class="card-footer-item has-background-info has-text-white has-text-weight-bold"
|
||||
@click="kickoff_pairing"
|
||||
>
|
||||
<span class="icon"><mdicon name="cellphone" size="16" /></span>
|
||||
<span class="is-size-7">Pair Remote</span>
|
||||
<mdicon class="icon" name="cellphone" size="16" />
|
||||
<span
|
||||
class="is-size-7"
|
||||
v-text="$t('dialog.remote-pairing.pair')"
|
||||
/>
|
||||
</a>
|
||||
</footer>
|
||||
</div>
|
||||
|
@ -6,138 +6,173 @@
|
||||
<div class="modal-content fd-modal-card">
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<p class="title is-4">
|
||||
{{ track.title }}
|
||||
</p>
|
||||
<p class="subtitle">
|
||||
{{ track.artist }}
|
||||
</p>
|
||||
<p class="title is-4" v-text="track.title" />
|
||||
<p class="subtitle" v-text="track.artist" />
|
||||
<div v-if="track.media_kind === 'podcast'" class="buttons">
|
||||
<a
|
||||
v-if="track.play_count > 0"
|
||||
class="button is-small"
|
||||
@click="mark_new"
|
||||
>Mark as new</a
|
||||
>
|
||||
v-text="$t('dialog.track.mark-as-new')"
|
||||
/>
|
||||
<a
|
||||
v-if="track.play_count === 0"
|
||||
class="button is-small"
|
||||
@click="mark_played"
|
||||
>Mark as played</a
|
||||
>
|
||||
v-text="$t('dialog.track.mark-as-played')"
|
||||
/>
|
||||
</div>
|
||||
<div class="content is-small">
|
||||
<p>
|
||||
<span class="heading">Album</span>
|
||||
<a class="title is-6 has-text-link" @click="open_album">{{
|
||||
track.album
|
||||
}}</a>
|
||||
<span class="heading" v-text="$t('dialog.track.album')" />
|
||||
<a
|
||||
class="title is-6 has-text-link"
|
||||
@click="open_album"
|
||||
v-text="track.album"
|
||||
/>
|
||||
</p>
|
||||
<p
|
||||
v-if="track.album_artist && track.media_kind !== 'audiobook'"
|
||||
>
|
||||
<span class="heading">Album artist</span>
|
||||
<a class="title is-6 has-text-link" @click="open_artist">{{
|
||||
track.album_artist
|
||||
}}</a>
|
||||
<span
|
||||
class="heading"
|
||||
v-text="$t('dialog.track.album-artist')"
|
||||
/>
|
||||
<a
|
||||
class="title is-6 has-text-link"
|
||||
@click="open_artist"
|
||||
v-text="track.album_artist"
|
||||
/>
|
||||
</p>
|
||||
<p v-if="track.composer">
|
||||
<span class="heading">Composer</span>
|
||||
<span class="title is-6">{{ track.composer }}</span>
|
||||
<span class="heading" v-text="$t('dialog.track.composer')" />
|
||||
<span class="title is-6" v-text="track.composer" />
|
||||
</p>
|
||||
<p v-if="track.date_released">
|
||||
<span class="heading">Release date</span>
|
||||
<span class="title is-6">{{
|
||||
$filters.date(track.date_released)
|
||||
}}</span>
|
||||
<span
|
||||
class="heading"
|
||||
v-text="$t('dialog.track.release-date')"
|
||||
/>
|
||||
<span
|
||||
class="title is-6"
|
||||
v-text="$filters.date(track.date_released)"
|
||||
/>
|
||||
</p>
|
||||
<p v-else-if="track.year > 0">
|
||||
<span class="heading">Year</span>
|
||||
<span class="title is-6">{{ track.year }}</span>
|
||||
<span class="heading" v-text="$t('dialog.track.year')" />
|
||||
<span class="title is-6" v-text="track.year" />
|
||||
</p>
|
||||
<p v-if="track.genre">
|
||||
<span class="heading">Genre</span>
|
||||
<a class="title is-6 has-text-link" @click="open_genre">{{
|
||||
track.genre
|
||||
}}</a>
|
||||
<span class="heading" v-text="$t('dialog.track.genre')" />
|
||||
<a
|
||||
class="title is-6 has-text-link"
|
||||
@click="open_genre"
|
||||
v-text="track.genre"
|
||||
/>
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading">Track / Disc</span>
|
||||
<span class="title is-6"
|
||||
>{{ track.track_number }} / {{ track.disc_number }}</span
|
||||
>
|
||||
<span class="heading" v-text="$t('dialog.track.position')" />
|
||||
<span
|
||||
class="title is-6"
|
||||
v-text="[track.disc_number, track.track_number].join(' / ')"
|
||||
/>
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading">Length</span>
|
||||
<span class="title is-6">{{
|
||||
$filters.durationInHours(track.length_ms)
|
||||
}}</span>
|
||||
<span class="heading" v-text="$t('dialog.track.duration')" />
|
||||
<span
|
||||
class="title is-6"
|
||||
v-text="$filters.durationInHours(track.length_ms)"
|
||||
/>
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading">Path</span>
|
||||
<span class="title is-6">{{ track.path }}</span>
|
||||
<span class="heading" v-text="$t('dialog.track.path')" />
|
||||
<span class="title is-6" v-text="track.path" />
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading">Type</span>
|
||||
<span class="title is-6"
|
||||
>{{ track.media_kind }} - {{ track.data_kind }}
|
||||
<span class="heading" v-text="$t('dialog.track.type')" />
|
||||
<span class="title is-6">
|
||||
<span
|
||||
v-text="[track.media_kind, track.data_kind].join(' - ')"
|
||||
/>
|
||||
<span
|
||||
v-if="track.data_kind === 'spotify'"
|
||||
class="has-text-weight-normal"
|
||||
>(<a @click="open_spotify_artist">artist</a>,
|
||||
<a @click="open_spotify_album">album</a>)</span
|
||||
></span
|
||||
>
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading">Quality</span>
|
||||
<span class="title is-6">
|
||||
{{ track.type }}
|
||||
<span v-if="track.samplerate">
|
||||
| {{ track.samplerate }} Hz</span
|
||||
>
|
||||
<span v-if="track.channels">
|
||||
| {{ $filters.channels(track.channels) }}</span
|
||||
>
|
||||
<span v-if="track.bitrate">
|
||||
| {{ track.bitrate }} Kb/s</span
|
||||
>
|
||||
(<a
|
||||
@click="open_spotify_artist"
|
||||
v-text="$t('dialog.track.spotify-artist')"
|
||||
/>,
|
||||
<a
|
||||
@click="open_spotify_album"
|
||||
v-text="$t('dialog.track.spotify-album')"
|
||||
/>)
|
||||
</span>
|
||||
</span>
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading">Added at</span>
|
||||
<span class="title is-6">{{
|
||||
$filters.datetime(track.time_added)
|
||||
}}</span>
|
||||
<span class="heading" v-text="$t('dialog.track.quality')" />
|
||||
<span class="title is-6">
|
||||
<span v-text="track.type" />
|
||||
<span
|
||||
v-if="track.samplerate"
|
||||
v-text="
|
||||
$t('dialog.track.samplerate', {
|
||||
rate: track.samplerate
|
||||
})
|
||||
"
|
||||
/>
|
||||
<span
|
||||
v-if="track.channels"
|
||||
v-text="
|
||||
$t('dialog.track.channels', {
|
||||
channels: $filters.channels(track.channels)
|
||||
})
|
||||
"
|
||||
/>
|
||||
<span
|
||||
v-if="track.bitrate"
|
||||
v-text="
|
||||
$t('dialog.track.bitrate', { rate: track.bitrate })
|
||||
"
|
||||
/>
|
||||
</span>
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading">Rating</span>
|
||||
<span class="title is-6"
|
||||
>{{ Math.floor(track.rating / 10) }} / 10</span
|
||||
>
|
||||
<span class="heading" v-text="$t('dialog.track.added-on')" />
|
||||
<span
|
||||
class="title is-6"
|
||||
v-text="$filters.datetime(track.time_added)"
|
||||
/>
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading" v-text="$t('dialog.track.rating')" />
|
||||
<span
|
||||
class="title is-6"
|
||||
v-text="
|
||||
$t('dialog.track.rating-value', {
|
||||
rating: Math.floor(track.rating / 10)
|
||||
})
|
||||
"
|
||||
/>
|
||||
</p>
|
||||
<p v-if="track.comment">
|
||||
<span class="heading">Comment</span>
|
||||
<span class="title is-6">{{ track.comment }}</span>
|
||||
<span class="heading" v-text="$t('dialog.track.comment')" />
|
||||
<span class="title is-6" v-text="track.comment" />
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<footer class="card-footer">
|
||||
<a class="card-footer-item has-text-dark" @click="queue_add">
|
||||
<span class="icon"
|
||||
><mdicon name="playlist-plus" size="16"
|
||||
/></span>
|
||||
<span class="is-size-7">Add</span>
|
||||
<mdicon class="icon" name="playlist-plus" size="16" />
|
||||
<span class="is-size-7" v-text="$t('dialog.track.add')" />
|
||||
</a>
|
||||
<a class="card-footer-item has-text-dark" @click="queue_add_next">
|
||||
<span class="icon"
|
||||
><mdicon name="playlist-play" size="16"
|
||||
/></span>
|
||||
<span class="is-size-7">Add Next</span>
|
||||
<mdicon class="icon" name="playlist-play" size="16" />
|
||||
<span class="is-size-7" v-text="$t('dialog.track.add-next')" />
|
||||
</a>
|
||||
<a class="card-footer-item has-text-dark" @click="play_track">
|
||||
<span class="icon"><mdicon name="play" size="16" /></span>
|
||||
<span class="is-size-7">Play</span>
|
||||
<mdicon class="icon" name="play" size="16" />
|
||||
<span class="is-size-7" v-text="$t('dialog.track.play')" />
|
||||
</a>
|
||||
</footer>
|
||||
</div>
|
||||
|
@ -1,40 +1,48 @@
|
||||
<template>
|
||||
<modal-dialog
|
||||
:show="show"
|
||||
title="Update library"
|
||||
:ok_action="library.updating ? '' : 'Rescan'"
|
||||
close_action="Close"
|
||||
:title="$t('dialog.update.title')"
|
||||
:ok_action="library.updating ? '' : $t('dialog.update.rescan')"
|
||||
:close_action="$t('dialog.update.cancel')"
|
||||
@ok="update_library"
|
||||
@close="close()"
|
||||
>
|
||||
<template #modal-content>
|
||||
<div v-if="!library.updating">
|
||||
<p class="mb-3">Scan for new, deleted and modified files</p>
|
||||
<p class="mb-3" v-text="$t('dialog.update.info')" />
|
||||
<div v-if="spotify_enabled || rss.tracks > 0" class="field">
|
||||
<div class="control">
|
||||
<div class="select is-small">
|
||||
<select v-model="update_dialog_scan_kind">
|
||||
<option value="">Update everything</option>
|
||||
<option value="files">Only update local library</option>
|
||||
<option v-if="spotify_enabled" value="spotify">
|
||||
Only update Spotify
|
||||
</option>
|
||||
<option v-if="rss.tracks > 0" value="rss">
|
||||
Only update RSS feeds
|
||||
</option>
|
||||
<option value="" v-text="$t('dialog.update.all')" />
|
||||
<option value="files" v-text="$t('dialog.update.local')" />
|
||||
<option
|
||||
v-if="spotify_enabled"
|
||||
value="spotify"
|
||||
v-text="$t('dialog.update.spotify')"
|
||||
/>
|
||||
<option
|
||||
v-if="rss.tracks > 0"
|
||||
value="rss"
|
||||
v-text="$t('dialog.update.feeds')"
|
||||
/>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label class="checkbox is-size-7 is-small">
|
||||
<input v-model="rescan_metadata" type="checkbox" />
|
||||
Rescan metadata for unmodified files
|
||||
<input
|
||||
v-model="rescan_metadata"
|
||||
type="checkbox"
|
||||
style="margin-right: 5px"
|
||||
/>
|
||||
<span v-text="$t('dialog.update.rescan-metadata')" />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else>
|
||||
<p class="mb-3">Library update in progress ...</p>
|
||||
<p class="mb-3" v-text="$t('dialog.update.progress')" />
|
||||
</div>
|
||||
</template>
|
||||
</modal-dialog>
|
||||
|
@ -12,9 +12,8 @@
|
||||
<div class="navbar-brand fd-expanded">
|
||||
<!-- Link to queue -->
|
||||
<navbar-item-link to="/" exact>
|
||||
<span class="icon"><mdicon name="playlist-play" size="24" /></span>
|
||||
<mdicon class="icon" name="playlist-play" size="24" />
|
||||
</navbar-item-link>
|
||||
|
||||
<!-- Now playing artist/title (not visible on "now playing" page) -->
|
||||
<router-link
|
||||
v-if="!is_now_playing_page"
|
||||
@ -25,16 +24,18 @@
|
||||
>
|
||||
<div class="is-clipped">
|
||||
<p class="is-size-7 fd-is-text-clipped">
|
||||
<strong>{{ now_playing.title }}</strong
|
||||
><br />
|
||||
{{ now_playing.artist
|
||||
}}<span v-if="now_playing.data_kind === 'url'">
|
||||
- {{ now_playing.album }}</span
|
||||
>
|
||||
<strong v-text="now_playing.title" />
|
||||
<br />
|
||||
<span v-text="now_playing.artist" />
|
||||
<span
|
||||
v-if="now_playing.data_kind === 'url'"
|
||||
v-text="
|
||||
$t('navigation.now-playing', { album: now_playing.album })
|
||||
"
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</router-link>
|
||||
|
||||
<!-- Skip previous (not visible on "now playing" page) -->
|
||||
<player-button-previous
|
||||
v-if="is_now_playing_page"
|
||||
@ -65,19 +66,17 @@
|
||||
class="navbar-item"
|
||||
:icon_size="24"
|
||||
/>
|
||||
|
||||
<!-- Player menu button (only visible on mobile and tablet) -->
|
||||
<a
|
||||
class="navbar-item fd-margin-left-auto is-hidden-desktop"
|
||||
@click="show_player_menu = !show_player_menu"
|
||||
>
|
||||
<span class="icon"
|
||||
><mdicon
|
||||
:name="show_player_menu ? 'chevron-down' : 'chevron-up'"
|
||||
size="18"
|
||||
/></span>
|
||||
<mdicon
|
||||
class="icon"
|
||||
:name="show_player_menu ? 'chevron-down' : 'chevron-up'"
|
||||
size="18"
|
||||
/>
|
||||
</a>
|
||||
|
||||
<!-- Player menu dropup menu (only visible on desktop) -->
|
||||
<div
|
||||
class="navbar-item has-dropdown has-dropdown-up fd-margin-left-auto is-hidden-touch"
|
||||
@ -87,13 +86,12 @@
|
||||
class="navbar-link is-arrowless"
|
||||
@click="show_player_menu = !show_player_menu"
|
||||
>
|
||||
<span class="icon"
|
||||
><mdicon
|
||||
:name="show_player_menu ? 'chevron-down' : 'chevron-up'"
|
||||
size="18"
|
||||
/></span>
|
||||
<mdicon
|
||||
class="icon"
|
||||
:name="show_player_menu ? 'chevron-down' : 'chevron-up'"
|
||||
size="18"
|
||||
/>
|
||||
</a>
|
||||
|
||||
<div
|
||||
class="navbar-dropdown is-right is-boxed"
|
||||
style="margin-right: 6px; margin-bottom: 6px; border-radius: 6px"
|
||||
@ -107,16 +105,16 @@
|
||||
class="button is-white is-small"
|
||||
@click="toggle_mute_volume"
|
||||
>
|
||||
<span class="icon"
|
||||
><mdicon
|
||||
:name="player.volume > 0 ? 'volume-high' : 'volume-off'"
|
||||
size="18"
|
||||
/></span>
|
||||
<mdicon
|
||||
class="icon"
|
||||
:name="player.volume > 0 ? 'volume-high' : 'volume-off'"
|
||||
size="18"
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
<div class="level-item fd-expanded">
|
||||
<div class="fd-expanded">
|
||||
<p class="heading">Volume</p>
|
||||
<p class="heading" v-text="$t('navigation.volume')" />
|
||||
<Slider
|
||||
v-model="player.volume"
|
||||
:min="0"
|
||||
@ -126,20 +124,11 @@
|
||||
:classes="{ target: 'slider' }"
|
||||
@change="set_volume"
|
||||
/>
|
||||
<!--range-slider
|
||||
class="slider fd-has-action"
|
||||
min="0"
|
||||
max="100"
|
||||
step="1"
|
||||
:value="player.volume"
|
||||
@change="set_volume">
|
||||
</range-slider-->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Outputs: master volume -->
|
||||
<hr class="fd-navbar-divider" />
|
||||
<navbar-item-output
|
||||
@ -147,7 +136,6 @@
|
||||
:key="output.id"
|
||||
:output="output"
|
||||
/>
|
||||
|
||||
<!-- Outputs: stream volume -->
|
||||
<hr class="fd-navbar-divider" />
|
||||
<div class="navbar-item">
|
||||
@ -157,15 +145,18 @@
|
||||
<a
|
||||
class="button is-white is-small"
|
||||
:class="{ 'is-loading': loading }"
|
||||
><span
|
||||
>
|
||||
<span
|
||||
class="icon fd-has-action"
|
||||
:class="{
|
||||
'has-text-grey-light': !playing && !loading,
|
||||
'is-loading': loading
|
||||
}"
|
||||
@click="togglePlay"
|
||||
><mdicon name="radio-tower" size="18" /></span
|
||||
></a>
|
||||
>
|
||||
<mdicon name="broadcast" size="18" />
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="level-item fd-expanded">
|
||||
<div class="fd-expanded">
|
||||
@ -173,10 +164,19 @@
|
||||
class="heading"
|
||||
:class="{ 'has-text-grey-light': !playing }"
|
||||
>
|
||||
HTTP stream
|
||||
<a href="stream.mp3"
|
||||
><span class="is-lowercase">(stream.mp3)</span></a
|
||||
<span v-text="$t('navigation.stream')" />
|
||||
<a
|
||||
href="stream.mp3"
|
||||
style="margin-left: 5px"
|
||||
target="_blank"
|
||||
>
|
||||
<mdicon
|
||||
class="icon"
|
||||
name="open-in-new"
|
||||
size="16"
|
||||
style="vertical-align: middle"
|
||||
/>
|
||||
</a>
|
||||
</p>
|
||||
<Slider
|
||||
v-model="stream_volume"
|
||||
@ -188,21 +188,11 @@
|
||||
:classes="{ target: 'slider' }"
|
||||
@change="set_stream_volume"
|
||||
/>
|
||||
<!--range-slider
|
||||
class="slider fd-has-action"
|
||||
min="0"
|
||||
max="100"
|
||||
step="1"
|
||||
:disabled="!playing"
|
||||
:value="stream_volume"
|
||||
@change="set_stream_volume">
|
||||
</range-slider-->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Playback controls -->
|
||||
<hr class="fd-navbar-divider" />
|
||||
<div class="navbar-item">
|
||||
@ -219,7 +209,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Player menu (only visible on mobile and tablet) -->
|
||||
<div
|
||||
class="navbar-menu is-hidden-desktop"
|
||||
@ -235,25 +224,23 @@
|
||||
<player-button-consume class="button" :icon_size="18" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr class="fd-navbar-divider" />
|
||||
|
||||
<!-- Outputs: master volume -->
|
||||
<div class="navbar-item">
|
||||
<div class="level is-mobile">
|
||||
<div class="level-left fd-expanded">
|
||||
<div class="level-item" style="flex-grow: 0">
|
||||
<a class="button is-white is-small" @click="toggle_mute_volume">
|
||||
<span class="icon"
|
||||
><mdicon
|
||||
:name="player.volume > 0 ? 'volume-high' : 'volume-off'"
|
||||
size="18"
|
||||
/></span>
|
||||
<mdicon
|
||||
class="icon"
|
||||
:name="player.volume > 0 ? 'volume-high' : 'volume-off'"
|
||||
size="18"
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
<div class="level-item fd-expanded">
|
||||
<div class="fd-expanded">
|
||||
<p class="heading">Volume</p>
|
||||
<p class="heading" v-text="$t('navigation.volume')" />
|
||||
<Slider
|
||||
v-model="player.volume"
|
||||
:min="0"
|
||||
@ -263,27 +250,17 @@
|
||||
:classes="{ target: 'slider' }"
|
||||
@change="set_volume"
|
||||
/>
|
||||
<!--range-slider
|
||||
class="slider fd-has-action"
|
||||
min="0"
|
||||
max="100"
|
||||
step="1"
|
||||
:value="player.volume"
|
||||
@change="set_volume">
|
||||
</range-slider-->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Outputs: speaker volumes -->
|
||||
<navbar-item-output
|
||||
v-for="output in outputs"
|
||||
:key="output.id"
|
||||
:output="output"
|
||||
/>
|
||||
|
||||
<!-- Outputs: stream volume -->
|
||||
<hr class="fd-navbar-divider" />
|
||||
<div class="navbar-item fd-has-margin-bottom">
|
||||
@ -301,7 +278,8 @@
|
||||
'is-loading': loading
|
||||
}"
|
||||
@click="togglePlay"
|
||||
><mdicon name="radio-tower" size="16" />
|
||||
>
|
||||
<mdicon name="broadcast" size="16" />
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
@ -311,10 +289,19 @@
|
||||
class="heading"
|
||||
:class="{ 'has-text-grey-light': !playing }"
|
||||
>
|
||||
HTTP stream
|
||||
<a href="stream.mp3"
|
||||
><span class="is-lowercase">(stream.mp3)</span></a
|
||||
<span v-text="$t('navigation.stream')" />
|
||||
<a
|
||||
href="stream.mp3"
|
||||
style="margin-left: 5px"
|
||||
target="_blank"
|
||||
>
|
||||
<mdicon
|
||||
class="icon"
|
||||
name="open-in-new"
|
||||
size="16"
|
||||
style="vertical-align: middle"
|
||||
/>
|
||||
</a>
|
||||
</p>
|
||||
<Slider
|
||||
v-model="stream_volume"
|
||||
@ -326,15 +313,6 @@
|
||||
:classes="{ target: 'slider' }"
|
||||
@change="set_stream_volume"
|
||||
/>
|
||||
<!-- range-slider
|
||||
class="slider fd-has-action"
|
||||
min="0"
|
||||
max="100"
|
||||
step="1"
|
||||
:disabled="!playing"
|
||||
:value="stream_volume"
|
||||
@change="set_stream_volume">
|
||||
</range-slider-->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -358,7 +336,6 @@ import PlayerButtonConsume from '@/components/PlayerButtonConsume.vue'
|
||||
import PlayerButtonRepeat from '@/components/PlayerButtonRepeat.vue'
|
||||
import PlayerButtonSeekBack from '@/components/PlayerButtonSeekBack.vue'
|
||||
import PlayerButtonSeekForward from '@/components/PlayerButtonSeekForward.vue'
|
||||
//import RangeSlider from 'vue-range-slider'
|
||||
import Slider from '@vueform/slider'
|
||||
import * as types from '@/store/mutation_types'
|
||||
|
||||
@ -367,7 +344,6 @@ export default {
|
||||
components: {
|
||||
NavbarItemLink,
|
||||
NavbarItemOutput,
|
||||
//RangeSlider,
|
||||
Slider,
|
||||
PlayerButtonPlayPause,
|
||||
PlayerButtonNext,
|
||||
@ -382,11 +358,9 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
old_volume: 0,
|
||||
|
||||
playing: false,
|
||||
loading: false,
|
||||
stream_volume: 10,
|
||||
|
||||
show_outputs_menu: false,
|
||||
show_desktop_outputs_menu: false
|
||||
}
|
||||
@ -488,7 +462,7 @@ export default {
|
||||
a.addEventListener('error', (e) => {
|
||||
this.closeAudio()
|
||||
this.$store.dispatch('add_notification', {
|
||||
text: 'HTTP stream error: failed to load stream or stopped loading due to network problem',
|
||||
text: this.$t('navigation.stream-error'),
|
||||
type: 'danger'
|
||||
})
|
||||
this.playing = false
|
||||
|
@ -18,9 +18,8 @@
|
||||
<p
|
||||
class="heading"
|
||||
:class="{ 'has-text-grey-light': !output.selected }"
|
||||
>
|
||||
{{ output.name }}
|
||||
</p>
|
||||
v-text="output.name"
|
||||
/>
|
||||
<Slider
|
||||
v-model="volume"
|
||||
:min="0"
|
||||
@ -31,15 +30,6 @@
|
||||
:classes="{ target: 'slider' }"
|
||||
@change="set_volume"
|
||||
/>
|
||||
<!--range-slider
|
||||
class="slider fd-has-action"
|
||||
min="0"
|
||||
max="100"
|
||||
step="1"
|
||||
:disabled="!output.selected"
|
||||
:value="volume"
|
||||
@change="set_volume" >
|
||||
</range-slider-->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -48,14 +38,12 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
//import RangeSlider from 'vue-range-slider'
|
||||
import Slider from '@vueform/slider'
|
||||
import webapi from '@/webapi'
|
||||
|
||||
export default {
|
||||
name: 'NavbarItemOutput',
|
||||
components: {
|
||||
// RangeSlider
|
||||
Slider
|
||||
},
|
||||
|
||||
|
@ -7,27 +7,26 @@
|
||||
>
|
||||
<div class="navbar-brand">
|
||||
<navbar-item-link v-if="is_visible_playlists" to="/playlists">
|
||||
<span class="icon"><mdicon name="music-box-multiple" size="16" /></span>
|
||||
<mdicon class="icon" name="music-box-multiple" size="16" />
|
||||
</navbar-item-link>
|
||||
<navbar-item-link v-if="is_visible_music" to="/music">
|
||||
<span class="icon"><mdicon name="music" size="16" /></span>
|
||||
<mdicon class="icon" name="music" size="16" />
|
||||
</navbar-item-link>
|
||||
<navbar-item-link v-if="is_visible_podcasts" to="/podcasts">
|
||||
<span class="icon"><mdicon name="microphone" size="16" /></span>
|
||||
<mdicon class="icon" name="podcast" size="16" />
|
||||
</navbar-item-link>
|
||||
<navbar-item-link v-if="is_visible_audiobooks" to="/audiobooks">
|
||||
<span class="icon"><mdicon name="book-open-variant" size="16" /></span>
|
||||
<mdicon class="icon" name="book-open-variant" size="16" />
|
||||
</navbar-item-link>
|
||||
<navbar-item-link v-if="is_visible_radio" to="/radio">
|
||||
<span class="icon"><mdicon name="radio" size="16" /></span>
|
||||
<mdicon class="icon" name="radio-tower" size="16" />
|
||||
</navbar-item-link>
|
||||
<navbar-item-link v-if="is_visible_files" to="/files">
|
||||
<span class="icon"><mdicon name="folder-open" size="16" /></span>
|
||||
<mdicon class="icon" name="folder-open" size="16" />
|
||||
</navbar-item-link>
|
||||
<navbar-item-link v-if="is_visible_search" to="/search">
|
||||
<span class="icon"><mdicon name="magnify" size="16" /></span>
|
||||
<mdicon class="icon" name="magnify" size="16" />
|
||||
</navbar-item-link>
|
||||
|
||||
<div
|
||||
class="navbar-burger"
|
||||
:class="{ 'is-active': show_burger_menu }"
|
||||
@ -38,10 +37,8 @@
|
||||
<span />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="navbar-menu" :class="{ 'is-active': show_burger_menu }">
|
||||
<div class="navbar-start" />
|
||||
|
||||
<div class="navbar-end">
|
||||
<!-- Burger menu entries -->
|
||||
<div
|
||||
@ -50,67 +47,76 @@
|
||||
@click="on_click_outside_settings"
|
||||
>
|
||||
<a class="navbar-link is-arrowless">
|
||||
<span class="icon is-hidden-touch"
|
||||
><mdicon name="menu" size="24"
|
||||
/></span>
|
||||
<span class="is-hidden-desktop has-text-weight-bold">OwnTone</span>
|
||||
<mdicon class="icon is-hidden-touch" name="menu" size="24" />
|
||||
<span
|
||||
class="is-hidden-desktop has-text-weight-bold"
|
||||
v-text="$t('navigation.title')"
|
||||
/>
|
||||
</a>
|
||||
|
||||
<div class="navbar-dropdown is-right">
|
||||
<navbar-item-link to="/playlists">
|
||||
<span class="icon"
|
||||
><mdicon name="music-box-multiple" size="16"
|
||||
/></span>
|
||||
<b>Playlists</b>
|
||||
<mdicon class="icon" name="music-box-multiple" size="16" />
|
||||
<b v-text="$t('navigation.playlists')" />
|
||||
</navbar-item-link>
|
||||
<navbar-item-link to="/music" exact>
|
||||
<span class="icon"><mdicon name="music" size="16" /></span>
|
||||
<b>Music</b>
|
||||
<mdicon class="icon" name="music" size="16" />
|
||||
<b v-text="$t('navigation.music')" />
|
||||
</navbar-item-link>
|
||||
<navbar-item-link to="/music/artists">
|
||||
<span class="fd-navbar-item-level2">Artists</span>
|
||||
<span
|
||||
class="fd-navbar-item-level2"
|
||||
v-text="$t('navigation.artists')"
|
||||
/>
|
||||
</navbar-item-link>
|
||||
<navbar-item-link to="/music/albums">
|
||||
<span class="fd-navbar-item-level2">Albums</span>
|
||||
<span
|
||||
class="fd-navbar-item-level2"
|
||||
v-text="$t('navigation.albums')"
|
||||
/>
|
||||
</navbar-item-link>
|
||||
<navbar-item-link to="/music/genres">
|
||||
<span class="fd-navbar-item-level2">Genres</span>
|
||||
<span
|
||||
class="fd-navbar-item-level2"
|
||||
v-text="$t('navigation.genres')"
|
||||
/>
|
||||
</navbar-item-link>
|
||||
<navbar-item-link v-if="spotify_enabled" to="/music/spotify">
|
||||
<span class="fd-navbar-item-level2">Spotify</span>
|
||||
<span
|
||||
class="fd-navbar-item-level2"
|
||||
v-text="$t('navigation.spotify')"
|
||||
/>
|
||||
</navbar-item-link>
|
||||
<navbar-item-link to="/podcasts">
|
||||
<span class="icon"><mdicon name="microphone" size="16" /></span>
|
||||
<b>Podcasts</b>
|
||||
<mdicon class="icon" name="podcast" size="16" />
|
||||
<b v-text="$t('navigation.podcasts')" />
|
||||
</navbar-item-link>
|
||||
<navbar-item-link to="/audiobooks">
|
||||
<span class="icon"
|
||||
><mdicon name="book-open-variant" size="16"
|
||||
/></span>
|
||||
<b>Audiobooks</b>
|
||||
<mdicon class="icon" name="book-open-variant" size="16" />
|
||||
<b v-text="$t('navigation.audiobooks')" />
|
||||
</navbar-item-link>
|
||||
<navbar-item-link to="/radio">
|
||||
<span class="icon"><mdicon name="radio" size="16" /></span>
|
||||
<b>Radio</b>
|
||||
<mdicon class="icon" name="radio-tower" size="16" />
|
||||
<b v-text="$t('navigation.radio')" />
|
||||
</navbar-item-link>
|
||||
<navbar-item-link to="/files">
|
||||
<span class="icon"><mdicon name="folder-open" size="16" /></span>
|
||||
<b>Files</b>
|
||||
<mdicon class="icon" name="folder-open" size="16" />
|
||||
<b v-text="$t('navigation.files')" />
|
||||
</navbar-item-link>
|
||||
<navbar-item-link to="/search">
|
||||
<span class="icon"><mdicon name="magnify" size="16" /></span>
|
||||
<b>Search</b>
|
||||
<mdicon class="icon" name="magnify" size="16" />
|
||||
<b v-text="$t('navigation.search')" />
|
||||
</navbar-item-link>
|
||||
<hr class="fd-navbar-divider" />
|
||||
|
||||
<navbar-item-link to="/settings/webinterface">
|
||||
Settings
|
||||
</navbar-item-link>
|
||||
<a class="navbar-item" @click.stop.prevent="open_update_dialog()">
|
||||
Update Library
|
||||
</a>
|
||||
<navbar-item-link to="/about"> About </navbar-item-link>
|
||||
|
||||
<navbar-item-link
|
||||
to="/settings/webinterface"
|
||||
v-text="$t('navigation.settings')"
|
||||
/>
|
||||
<a
|
||||
class="navbar-item"
|
||||
@click.stop.prevent="open_update_dialog()"
|
||||
v-text="$t('navigation.update-library')"
|
||||
/>
|
||||
<navbar-item-link to="/about" v-text="$t('navigation.about')" />
|
||||
<div
|
||||
class="navbar-item is-hidden-desktop"
|
||||
style="margin-bottom: 2.5rem"
|
||||
@ -119,7 +125,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-show="show_settings_menu"
|
||||
class="is-overlay"
|
||||
|
@ -12,7 +12,7 @@
|
||||
]"
|
||||
>
|
||||
<button class="delete" @click="remove(notification)" />
|
||||
{{ notification.text }}
|
||||
<span v-text="notification.text" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<a :class="{ 'is-warning': is_consume }" @click="toggle_consume_mode">
|
||||
<span class="icon"><mdicon name="fire" :size="icon_size" /></span>
|
||||
<mdicon class="icon" name="fire" :size="icon_size" />
|
||||
</a>
|
||||
</template>
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<a :disabled="disabled" @click="play_next">
|
||||
<span class="icon"><mdicon name="skip-forward" :size="icon_size" /></span>
|
||||
<mdicon class="icon" name="skip-forward" :size="icon_size" />
|
||||
</a>
|
||||
</template>
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<a :disabled="disabled" @click="toggle_play_pause">
|
||||
<span class="icon"><mdicon :name="icon_name" :size="icon_size" /></span>
|
||||
<mdicon class="icon" :name="icon_name" :size="icon_size" />
|
||||
</a>
|
||||
</template>
|
||||
|
||||
@ -49,7 +49,7 @@ export default {
|
||||
if (this.disabled) {
|
||||
if (this.show_disabled_message) {
|
||||
this.$store.dispatch('add_notification', {
|
||||
text: 'Queue is empty',
|
||||
text: this.$t('server.empty-queue'),
|
||||
type: 'info',
|
||||
topic: 'connection',
|
||||
timeout: 2000
|
||||
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<a :disabled="disabled" @click="play_previous">
|
||||
<span class="icon"><mdicon name="skip-backward" :size="icon_size" /></span>
|
||||
<mdicon class="icon" name="skip-backward" :size="icon_size" />
|
||||
</a>
|
||||
</template>
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<a :class="{ 'is-warning': !is_repeat_off }" @click="toggle_repeat_mode">
|
||||
<span class="icon"><mdicon :name="icon_name" :size="icon_size" /></span>
|
||||
<mdicon class="icon" :name="icon_name" :size="icon_size" />
|
||||
</a>
|
||||
</template>
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<a v-if="visible" :disabled="disabled" @click="seek">
|
||||
<span class="icon"><mdicon name="rewind" :size="icon_size" /></span>
|
||||
<mdicon class="icon" name="rewind" :size="icon_size" />
|
||||
</a>
|
||||
</template>
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<a v-if="visible" :disabled="disabled" @click="seek">
|
||||
<span class="icon"><mdicon name="fast-forward" :size="icon_size" /></span>
|
||||
<mdicon class="icon" name="fast-forward" :size="icon_size" />
|
||||
</a>
|
||||
</template>
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<a :class="{ 'is-warning': is_shuffle }" @click="toggle_shuffle_mode">
|
||||
<span class="icon"><mdicon :name="icon_name" :size="icon_size" /></span>
|
||||
<mdicon class="icon" :name="icon_name" :size="icon_size" />
|
||||
</a>
|
||||
</template>
|
||||
|
||||
|
@ -1,22 +1,19 @@
|
||||
<template>
|
||||
<div class="field">
|
||||
<label class="checkbox">
|
||||
<label class="switch">
|
||||
<input
|
||||
ref="settings_checkbox"
|
||||
ref="setting"
|
||||
type="checkbox"
|
||||
:checked="value"
|
||||
style="margin-right: 5px"
|
||||
@change="set_update_timer"
|
||||
/>
|
||||
<slot name="label" />
|
||||
<i
|
||||
class="is-size-7"
|
||||
:class="{
|
||||
'has-text-info': statusUpdate === 'success',
|
||||
'has-text-danger': statusUpdate === 'error'
|
||||
}"
|
||||
>
|
||||
{{ info }}</i
|
||||
>
|
||||
:class="{ 'has-text-info': is_success, 'has-text-danger': is_error }"
|
||||
v-text="info"
|
||||
/>
|
||||
</label>
|
||||
<p v-if="$slots['info']" class="help">
|
||||
<slot name="info" />
|
||||
@ -30,15 +27,12 @@ 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: ''
|
||||
}
|
||||
},
|
||||
@ -65,11 +59,19 @@ export default {
|
||||
|
||||
info() {
|
||||
if (this.statusUpdate === 'success') {
|
||||
return '(setting saved)'
|
||||
return this.$t('setting.saved')
|
||||
} else if (this.statusUpdate === 'error') {
|
||||
return '(error saving setting)'
|
||||
return this.$t('setting.not-saved')
|
||||
}
|
||||
return ''
|
||||
},
|
||||
|
||||
is_success() {
|
||||
return this.statusUpdate === 'success'
|
||||
},
|
||||
|
||||
is_error() {
|
||||
return this.statusUpdate === 'error'
|
||||
}
|
||||
},
|
||||
|
||||
@ -81,7 +83,7 @@ export default {
|
||||
}
|
||||
|
||||
this.statusUpdate = ''
|
||||
const newValue = this.$refs.settings_checkbox.checked
|
||||
const newValue = this.$refs.setting.checked
|
||||
if (newValue !== this.value) {
|
||||
this.timerId = window.setTimeout(this.update_setting, this.timerDelay)
|
||||
}
|
||||
@ -90,8 +92,8 @@ export default {
|
||||
update_setting() {
|
||||
this.timerId = -1
|
||||
|
||||
const newValue = this.$refs.settings_checkbox.checked
|
||||
console.log(this.$refs.settings_checkbox)
|
||||
const newValue = this.$refs.setting.checked
|
||||
console.log(this.$refs.setting)
|
||||
if (newValue === this.value) {
|
||||
this.statusUpdate = ''
|
||||
return
|
||||
@ -110,7 +112,7 @@ export default {
|
||||
})
|
||||
.catch(() => {
|
||||
this.statusUpdate = 'error'
|
||||
this.$refs.settings_checkbox.checked = this.value
|
||||
this.$refs.setting.checked = this.value
|
||||
})
|
||||
.finally(() => {
|
||||
this.timerId = window.setTimeout(this.clear_status, this.timerDelay)
|
||||
|
@ -5,17 +5,13 @@
|
||||
<slot name="label" />
|
||||
<i
|
||||
class="is-size-7"
|
||||
:class="{
|
||||
'has-text-info': statusUpdate === 'success',
|
||||
'has-text-danger': statusUpdate === 'error'
|
||||
}"
|
||||
>
|
||||
{{ info }}</i
|
||||
>
|
||||
:class="{ 'has-text-info': is_success, 'has-text-danger': is_error }"
|
||||
v-text="info"
|
||||
/>
|
||||
</label>
|
||||
<div class="control">
|
||||
<input
|
||||
ref="settings_number"
|
||||
ref="setting"
|
||||
class="input"
|
||||
type="number"
|
||||
min="0"
|
||||
@ -38,14 +34,12 @@ import * as types from '@/store/mutation_types'
|
||||
|
||||
export default {
|
||||
name: 'SettingsIntfield',
|
||||
|
||||
props: ['category_name', 'option_name', 'placeholder', 'disabled'],
|
||||
|
||||
data() {
|
||||
return {
|
||||
timerDelay: 2000,
|
||||
timerId: -1,
|
||||
|
||||
statusUpdate: ''
|
||||
}
|
||||
},
|
||||
@ -72,11 +66,19 @@ export default {
|
||||
|
||||
info() {
|
||||
if (this.statusUpdate === 'success') {
|
||||
return '(setting saved)'
|
||||
return this.$t('setting.saved')
|
||||
} else if (this.statusUpdate === 'error') {
|
||||
return '(error saving setting)'
|
||||
return this.$t('setting.not-saved')
|
||||
}
|
||||
return ''
|
||||
},
|
||||
|
||||
is_success() {
|
||||
return this.statusUpdate === 'success'
|
||||
},
|
||||
|
||||
is_error() {
|
||||
return this.statusUpdate === 'error'
|
||||
}
|
||||
},
|
||||
|
||||
@ -88,7 +90,7 @@ export default {
|
||||
}
|
||||
|
||||
this.statusUpdate = ''
|
||||
const newValue = this.$refs.settings_number.value
|
||||
const newValue = this.$refs.setting.value
|
||||
if (newValue !== this.value) {
|
||||
this.timerId = window.setTimeout(this.update_setting, this.timerDelay)
|
||||
}
|
||||
@ -97,7 +99,7 @@ export default {
|
||||
update_setting() {
|
||||
this.timerId = -1
|
||||
|
||||
const newValue = this.$refs.settings_number.value
|
||||
const newValue = this.$refs.setting.value
|
||||
if (newValue === this.value) {
|
||||
this.statusUpdate = ''
|
||||
return
|
||||
@ -116,7 +118,7 @@ export default {
|
||||
})
|
||||
.catch(() => {
|
||||
this.statusUpdate = 'error'
|
||||
this.$refs.settings_number.value = this.value
|
||||
this.$refs.setting.value = this.value
|
||||
})
|
||||
.finally(() => {
|
||||
this.timerId = window.setTimeout(this.clear_status, this.timerDelay)
|
||||
|
@ -5,17 +5,13 @@
|
||||
<slot name="label" />
|
||||
<i
|
||||
class="is-size-7"
|
||||
:class="{
|
||||
'has-text-info': statusUpdate === 'success',
|
||||
'has-text-danger': statusUpdate === 'error'
|
||||
}"
|
||||
>
|
||||
{{ info }}</i
|
||||
>
|
||||
:class="{ 'has-text-info': is_success, 'has-text-danger': is_error }"
|
||||
v-text="info"
|
||||
/>
|
||||
</label>
|
||||
<div class="control">
|
||||
<input
|
||||
ref="settings_text"
|
||||
ref="setting"
|
||||
class="input"
|
||||
type="text"
|
||||
:placeholder="placeholder"
|
||||
@ -43,8 +39,6 @@ export default {
|
||||
return {
|
||||
timerDelay: 2000,
|
||||
timerId: -1,
|
||||
|
||||
// <empty>: default/no changes, 'success': update succesful, 'error': update failed
|
||||
statusUpdate: ''
|
||||
}
|
||||
},
|
||||
@ -71,11 +65,19 @@ export default {
|
||||
|
||||
info() {
|
||||
if (this.statusUpdate === 'success') {
|
||||
return '(setting saved)'
|
||||
return this.$t('setting.saved')
|
||||
} else if (this.statusUpdate === 'error') {
|
||||
return '(error saving setting)'
|
||||
return this.$t('setting.not-saved')
|
||||
}
|
||||
return ''
|
||||
},
|
||||
|
||||
is_success() {
|
||||
return this.statusUpdate === 'success'
|
||||
},
|
||||
|
||||
is_error() {
|
||||
return this.statusUpdate === 'error'
|
||||
}
|
||||
},
|
||||
|
||||
@ -87,7 +89,7 @@ export default {
|
||||
}
|
||||
|
||||
this.statusUpdate = ''
|
||||
const newValue = this.$refs.settings_text.value
|
||||
const newValue = this.$refs.setting.value
|
||||
if (newValue !== this.value) {
|
||||
this.timerId = window.setTimeout(this.update_setting, this.timerDelay)
|
||||
}
|
||||
@ -96,7 +98,7 @@ export default {
|
||||
update_setting() {
|
||||
this.timerId = -1
|
||||
|
||||
const newValue = this.$refs.settings_text.value
|
||||
const newValue = this.$refs.setting.value
|
||||
if (newValue === this.value) {
|
||||
this.statusUpdate = ''
|
||||
return
|
||||
@ -115,7 +117,7 @@ export default {
|
||||
})
|
||||
.catch(() => {
|
||||
this.statusUpdate = 'error'
|
||||
this.$refs.settings_text.value = this.value
|
||||
this.$refs.setting.value = this.value
|
||||
})
|
||||
.finally(() => {
|
||||
this.timerId = window.setTimeout(this.clear_status, this.timerDelay)
|
||||
|
@ -4,15 +4,16 @@
|
||||
<slot name="artwork" />
|
||||
</div>
|
||||
<div class="media-content fd-has-action is-clipped">
|
||||
<h1 class="title is-6">
|
||||
{{ album.name }}
|
||||
</h1>
|
||||
<h1 class="title is-6" v-text="album.name" />
|
||||
<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 }}, {{ $filters.date(album.release_date) }})
|
||||
<b v-text="album.artists[0].name" />
|
||||
</h2>
|
||||
<h2
|
||||
class="subtitle is-7 has-text-grey has-text-weight-normal"
|
||||
v-text="
|
||||
[album.album_type, $filters.date(album.release_date)].join(', ')
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
<div class="media-right">
|
||||
<slot name="actions" />
|
||||
|
@ -1,9 +1,7 @@
|
||||
<template>
|
||||
<div class="media">
|
||||
<div class="media-content fd-has-action is-clipped" @click="open_artist">
|
||||
<h1 class="title is-6">
|
||||
{{ artist.name }}
|
||||
</h1>
|
||||
<h1 class="title is-6" v-text="artist.name" />
|
||||
</div>
|
||||
<div class="media-right">
|
||||
<slot name="actions" />
|
||||
|
@ -1,12 +1,8 @@
|
||||
<template>
|
||||
<div class="media">
|
||||
<div class="media-content fd-has-action is-clipped" @click="open_playlist">
|
||||
<h1 class="title is-6">
|
||||
{{ playlist.name }}
|
||||
</h1>
|
||||
<h2 class="subtitle is-7">
|
||||
{{ playlist.owner.display_name }}
|
||||
</h2>
|
||||
<h1 class="title is-6" v-text="playlist.name" />
|
||||
<h2 class="subtitle is-7" v-text="playlist.owner.display_name" />
|
||||
</div>
|
||||
<div class="media-right">
|
||||
<slot name="actions" />
|
||||
|
@ -4,9 +4,8 @@
|
||||
<h1
|
||||
class="title is-6"
|
||||
:class="{ 'has-text-grey-light': track.is_playable === false }"
|
||||
>
|
||||
{{ track.name }}
|
||||
</h1>
|
||||
v-text="track.name"
|
||||
/>
|
||||
<h2
|
||||
class="subtitle is-7"
|
||||
:class="{
|
||||
@ -14,13 +13,18 @@
|
||||
'has-text-grey-light': track.is_playable === false
|
||||
}"
|
||||
>
|
||||
<b>{{ track.artists[0].name }}</b>
|
||||
<b v-text="track.artists[0].name" />
|
||||
</h2>
|
||||
<h2 v-if="track.is_playable === false" class="subtitle is-7">
|
||||
(Track is not playable<span
|
||||
(<span v-text="$t('list.spotify.not-playable-track')" />
|
||||
<span
|
||||
v-if="track.restrictions && track.restrictions.reason"
|
||||
>, restriction reason: {{ track.restrictions.reason }}</span
|
||||
>)
|
||||
v-text="
|
||||
$t('list.spotify.restriction-reason', {
|
||||
reason: track.restrictions.reason
|
||||
})
|
||||
"
|
||||
/>)
|
||||
</h2>
|
||||
</div>
|
||||
<div class="media-right">
|
||||
@ -34,9 +38,7 @@ import webapi from '@/webapi'
|
||||
|
||||
export default {
|
||||
name: 'SpotifyListItemTrack',
|
||||
|
||||
props: ['track', 'position', 'album', 'context_uri'],
|
||||
|
||||
methods: {
|
||||
play: function () {
|
||||
webapi.player_play_uri(this.context_uri, false, this.position)
|
||||
|
@ -18,45 +18,64 @@
|
||||
/>
|
||||
</figure>
|
||||
<p class="title is-4">
|
||||
<a class="has-text-link" @click="open_album">{{
|
||||
album.name
|
||||
}}</a>
|
||||
<a
|
||||
class="has-text-link"
|
||||
@click="open_album"
|
||||
v-text="album.name"
|
||||
/>
|
||||
</p>
|
||||
<div class="content is-small">
|
||||
<p>
|
||||
<span class="heading">Album artist</span>
|
||||
<a class="title is-6 has-text-link" @click="open_artist">{{
|
||||
album.artists[0].name
|
||||
}}</a>
|
||||
<span
|
||||
class="heading"
|
||||
v-text="$t('dialog.spotify.album.album-artist')"
|
||||
/>
|
||||
<a
|
||||
class="title is-6 has-text-link"
|
||||
@click="open_artist"
|
||||
v-text="album.artists[0].name"
|
||||
/>
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading">Release date</span>
|
||||
<span class="title is-6">{{
|
||||
$filters.date(album.release_date)
|
||||
}}</span>
|
||||
<span
|
||||
class="heading"
|
||||
v-text="$t('dialog.spotify.album.release-date')"
|
||||
/>
|
||||
<span
|
||||
class="title is-6"
|
||||
v-text="$filters.date(album.release_date)"
|
||||
/>
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading">Type</span>
|
||||
<span class="title is-6">{{ album.album_type }}</span>
|
||||
<span
|
||||
class="heading"
|
||||
v-text="$t('dialog.spotify.album.type')"
|
||||
/>
|
||||
<span class="title is-6" v-text="album.album_type" />
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<footer class="card-footer">
|
||||
<a class="card-footer-item has-text-dark" @click="queue_add">
|
||||
<span class="icon"
|
||||
><mdicon name="playlist-plus" size="16"
|
||||
/></span>
|
||||
<span class="is-size-7">Add</span>
|
||||
<mdicon class="icon" name="playlist-plus" size="16" />
|
||||
<span
|
||||
class="is-size-7"
|
||||
v-text="$t('dialog.spotify.album.add')"
|
||||
/>
|
||||
</a>
|
||||
<a class="card-footer-item has-text-dark" @click="queue_add_next">
|
||||
<span class="icon"
|
||||
><mdicon name="playlist-play" size="16"
|
||||
/></span>
|
||||
<span class="is-size-7">Add Next</span>
|
||||
<mdicon class="icon" name="playlist-play" size="16" />
|
||||
<span
|
||||
class="is-size-7"
|
||||
v-text="$t('dialog.spotify.album.add-next')"
|
||||
/>
|
||||
</a>
|
||||
<a class="card-footer-item has-text-dark" @click="play">
|
||||
<span class="icon"><mdicon name="play" size="16" /></span>
|
||||
<span class="is-size-7">Play</span>
|
||||
<mdicon class="icon" name="play" size="16" />
|
||||
<span
|
||||
class="is-size-7"
|
||||
v-text="$t('dialog.spotify.album.play')"
|
||||
/>
|
||||
</a>
|
||||
</footer>
|
||||
</div>
|
||||
|
@ -7,40 +7,55 @@
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<p class="title is-4">
|
||||
<a class="has-text-link" @click="open_artist">{{
|
||||
artist.name
|
||||
}}</a>
|
||||
<a
|
||||
class="has-text-link"
|
||||
@click="open_artist"
|
||||
v-text="artist.name"
|
||||
/>
|
||||
</p>
|
||||
<div class="content is-small">
|
||||
<p>
|
||||
<span class="heading">Popularity / Followers</span>
|
||||
<span class="title is-6"
|
||||
>{{ artist.popularity }} /
|
||||
{{ artist.followers.total }}</span
|
||||
>
|
||||
<span
|
||||
class="heading"
|
||||
v-text="$t('dialog.spotify.artist.popularity')"
|
||||
/>
|
||||
<span
|
||||
class="title is-6"
|
||||
v-text="
|
||||
[artist.popularity, artist.followers.total].join(' / ')
|
||||
"
|
||||
/>
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading">Genres</span>
|
||||
<span class="title is-6">{{ artist.genres.join(', ') }}</span>
|
||||
<span
|
||||
class="heading"
|
||||
v-text="$t('dialog.spotify.artist.genres')"
|
||||
/>
|
||||
<span class="title is-6" v-text="artist.genres.join(', ')" />
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<footer class="card-footer">
|
||||
<a class="card-footer-item has-text-dark" @click="queue_add">
|
||||
<span class="icon"
|
||||
><mdicon name="playlist-plus" size="16"
|
||||
/></span>
|
||||
<span class="is-size-7">Add</span>
|
||||
<mdicon class="icon" name="playlist-plus" size="16" />
|
||||
<span
|
||||
class="is-size-7"
|
||||
v-text="$t('dialog.spotify.artist.add')"
|
||||
/>
|
||||
</a>
|
||||
<a class="card-footer-item has-text-dark" @click="queue_add_next">
|
||||
<span class="icon"
|
||||
><mdicon name="playlist-play" size="16"
|
||||
/></span>
|
||||
<span class="is-size-7">Add Next</span>
|
||||
<mdicon class="icon" name="playlist-play" size="16" />
|
||||
<span
|
||||
class="is-size-7"
|
||||
v-text="$t('dialog.spotify.artist.add-next')"
|
||||
/>
|
||||
</a>
|
||||
<a class="card-footer-item has-text-dark" @click="play">
|
||||
<span class="icon"><mdicon name="play" size="16" /></span>
|
||||
<span class="is-size-7">Play</span>
|
||||
<mdicon class="icon" name="play" size="16" />
|
||||
<span
|
||||
class="is-size-7"
|
||||
v-text="$t('dialog.spotify.artist.play')"
|
||||
/>
|
||||
</a>
|
||||
</footer>
|
||||
</div>
|
||||
|
@ -7,43 +7,60 @@
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<p class="title is-4">
|
||||
<a class="has-text-link" @click="open_playlist">{{
|
||||
playlist.name
|
||||
}}</a>
|
||||
<a
|
||||
class="has-text-link"
|
||||
@click="open_playlist"
|
||||
v-text="playlist.name"
|
||||
/>
|
||||
</p>
|
||||
<div class="content is-small">
|
||||
<p>
|
||||
<span class="heading">Owner</span>
|
||||
<span class="title is-6">{{
|
||||
playlist.owner.display_name
|
||||
}}</span>
|
||||
<span
|
||||
class="heading"
|
||||
v-text="$t('dialog.spotify.playlist.owner')"
|
||||
/>
|
||||
<span
|
||||
class="title is-6"
|
||||
v-text="playlist.owner.display_name"
|
||||
/>
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading">Tracks</span>
|
||||
<span class="title is-6">{{ playlist.tracks.total }}</span>
|
||||
<span
|
||||
class="heading"
|
||||
v-text="$t('dialog.spotify.playlist.tracks')"
|
||||
/>
|
||||
<span class="title is-6" v-text="playlist.tracks.total" />
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading">Path</span>
|
||||
<span class="title is-6">{{ playlist.uri }}</span>
|
||||
<span
|
||||
class="heading"
|
||||
v-text="$t('dialog.spotify.playlist.path')"
|
||||
/>
|
||||
<span class="title is-6" v-text="playlist.uri" />
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<footer class="card-footer">
|
||||
<a class="card-footer-item has-text-dark" @click="queue_add">
|
||||
<span class="icon"
|
||||
><mdicon name="playlist-plus" size="16"
|
||||
/></span>
|
||||
<span class="is-size-7">Add</span>
|
||||
<mdicon class="icon" name="playlist-plus" size="16" />
|
||||
<span
|
||||
class="is-size-7"
|
||||
v-text="$t('dialog.spotify.playlist.add')"
|
||||
/>
|
||||
</a>
|
||||
<a class="card-footer-item has-text-dark" @click="queue_add_next">
|
||||
<span class="icon"
|
||||
><mdicon name="playlist-play" size="16"
|
||||
/></span>
|
||||
<span class="is-size-7">Add Next</span>
|
||||
<mdicon class="icon" name="playlist-play" size="16" />
|
||||
<span
|
||||
class="is-size-7"
|
||||
v-text="$t('dialog.spotify.playlist.add-next')"
|
||||
/>
|
||||
</a>
|
||||
<a class="card-footer-item has-text-dark" @click="play">
|
||||
<span class="icon"><mdicon name="play" size="16" /></span>
|
||||
<span class="is-size-7">Play</span>
|
||||
<mdicon class="icon" name="play" size="16" />
|
||||
<span
|
||||
class="is-size-7"
|
||||
v-text="$t('dialog.spotify.playlist.play')"
|
||||
/>
|
||||
</a>
|
||||
</footer>
|
||||
</div>
|
||||
|
@ -6,65 +6,91 @@
|
||||
<div class="modal-content fd-modal-card">
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<p class="title is-4">
|
||||
{{ track.name }}
|
||||
</p>
|
||||
<p class="subtitle">
|
||||
{{ track.artists[0].name }}
|
||||
</p>
|
||||
<p class="title is-4" v-text="track.name" />
|
||||
<p class="subtitle" v-text="track.artists[0].name" />
|
||||
<div class="content is-small">
|
||||
<p>
|
||||
<span class="heading">Album</span>
|
||||
<a class="title is-6 has-text-link" @click="open_album">{{
|
||||
album.name
|
||||
}}</a>
|
||||
<span
|
||||
class="heading"
|
||||
v-text="$t('dialog.spotify.track.album')"
|
||||
/>
|
||||
<a
|
||||
class="title is-6 has-text-link"
|
||||
@click="open_album"
|
||||
v-text="album.name"
|
||||
/>
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading">Album artist</span>
|
||||
<a class="title is-6 has-text-link" @click="open_artist">{{
|
||||
album.artists[0].name
|
||||
}}</a>
|
||||
<span
|
||||
class="heading"
|
||||
v-text="$t('dialog.spotify.track.album-artist')"
|
||||
/>
|
||||
<a
|
||||
class="title is-6 has-text-link"
|
||||
@click="open_artist"
|
||||
v-text="album.artists[0].name"
|
||||
/>
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading">Release date</span>
|
||||
<span class="title is-6">{{
|
||||
$filters.date(album.release_date)
|
||||
}}</span>
|
||||
<span
|
||||
class="heading"
|
||||
v-text="$t('dialog.spotify.track.release-date')"
|
||||
/>
|
||||
<span
|
||||
class="title is-6"
|
||||
v-text="$filters.date(album.release_date)"
|
||||
/>
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading">Track / Disc</span>
|
||||
<span class="title is-6"
|
||||
>{{ track.track_number }} / {{ track.disc_number }}</span
|
||||
>
|
||||
<span
|
||||
class="heading"
|
||||
v-text="$t('dialog.spotify.track.position')"
|
||||
/>
|
||||
<span
|
||||
class="title is-6"
|
||||
v-text="[track.disc_number, track.track_number].join(' / ')"
|
||||
/>
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading">Length</span>
|
||||
<span class="title is-6">{{
|
||||
$filters.durationInHours(track.duration_ms)
|
||||
}}</span>
|
||||
<span
|
||||
class="heading"
|
||||
v-text="$t('dialog.spotify.track.duration')"
|
||||
/>
|
||||
<span
|
||||
class="title is-6"
|
||||
v-text="$filters.durationInHours(track.duration_ms)"
|
||||
/>
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading">Path</span>
|
||||
<span class="title is-6">{{ track.uri }}</span>
|
||||
<span
|
||||
class="heading"
|
||||
v-text="$t('dialog.spotify.track.path')"
|
||||
/>
|
||||
<span class="title is-6" v-text="track.uri" />
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<footer class="card-footer">
|
||||
<a class="card-footer-item has-text-dark" @click="queue_add">
|
||||
<span class="icon"
|
||||
><mdicon name="playlist-plus" size="16"
|
||||
/></span>
|
||||
<span class="is-size-7">Add</span>
|
||||
<mdicon class="icon" name="playlist-plus" size="16" />
|
||||
<span
|
||||
class="is-size-7"
|
||||
v-text="$t('dialog.spotify.track.add')"
|
||||
/>
|
||||
</a>
|
||||
<a class="card-footer-item has-text-dark" @click="queue_add_next">
|
||||
<span class="icon"
|
||||
><mdicon name="playlist-play" size="16"
|
||||
/></span>
|
||||
<span class="is-size-7">Add Next</span>
|
||||
<mdicon class="icon" name="playlist-play" size="16" />
|
||||
<span
|
||||
class="is-size-7"
|
||||
v-text="$t('dialog.spotify.track.add-next')"
|
||||
/>
|
||||
</a>
|
||||
<a class="card-footer-item has-text-dark" @click="play">
|
||||
<span class="icon"><mdicon name="play" size="16" /></span>
|
||||
<span class="is-size-7">Play</span>
|
||||
<mdicon class="icon" name="play" size="16" />
|
||||
<span
|
||||
class="is-size-7"
|
||||
v-text="$t('dialog.spotify.track.play')"
|
||||
/>
|
||||
</a>
|
||||
</footer>
|
||||
</div>
|
||||
|
@ -12,10 +12,12 @@
|
||||
>
|
||||
<li :class="{ 'is-active': isActive }">
|
||||
<a @click="navigate" @keypress.enter="navigate">
|
||||
<span class="icon is-small"
|
||||
><mdicon name="account-music" size="16"
|
||||
/></span>
|
||||
<span class="">Authors</span>
|
||||
<mdicon
|
||||
class="icon is-small"
|
||||
name="account-music"
|
||||
size="16"
|
||||
/>
|
||||
<span v-text="$t('tabs.audiobooks.authors')" />
|
||||
</a>
|
||||
</li>
|
||||
</router-link>
|
||||
@ -26,10 +28,8 @@
|
||||
>
|
||||
<li :class="{ 'is-active': isActive }">
|
||||
<a @click="navigate" @keypress.enter="navigate">
|
||||
<span class="icon is-small"
|
||||
><mdicon name="album" size="16"
|
||||
/></span>
|
||||
<span class="">Audiobooks</span>
|
||||
<mdicon class="icon is-small" name="album" size="16" />
|
||||
<span v-text="$t('tabs.audiobooks.audiobooks')" />
|
||||
</a>
|
||||
</li>
|
||||
</router-link>
|
||||
|
@ -12,10 +12,8 @@
|
||||
>
|
||||
<li :class="{ 'is-active': isActive }">
|
||||
<a @click="navigate" @keypress.enter="navigate">
|
||||
<span class="icon is-small"
|
||||
><mdicon name="web" size="16"
|
||||
/></span>
|
||||
<span class="">Browse</span>
|
||||
<mdicon class="icon is-small" name="web" size="16" />
|
||||
<span v-text="$t('page.settings.tabs.music.browse')" />
|
||||
</a>
|
||||
</li>
|
||||
</router-link>
|
||||
@ -26,10 +24,12 @@
|
||||
>
|
||||
<li :class="{ 'is-active': isActive }">
|
||||
<a @click="navigate" @keypress.enter="navigate">
|
||||
<span class="icon is-small"
|
||||
><mdicon name="account-music" size="16"
|
||||
/></span>
|
||||
<span class="">Artists</span>
|
||||
<mdicon
|
||||
class="icon is-small"
|
||||
name="account-music"
|
||||
size="16"
|
||||
/>
|
||||
<span v-text="$t('page.settings.tabs.music.artists')" />
|
||||
</a>
|
||||
</li>
|
||||
</router-link>
|
||||
@ -40,10 +40,8 @@
|
||||
>
|
||||
<li :class="{ 'is-active': isActive }">
|
||||
<a @click="navigate" @keypress.enter="navigate">
|
||||
<span class="icon is-small"
|
||||
><mdicon name="album" size="16"
|
||||
/></span>
|
||||
<span class="">Albums</span>
|
||||
<mdicon class="icon is-small" name="album" size="16" />
|
||||
<span v-text="$t('page.settings.tabs.music.albums')" />
|
||||
</a>
|
||||
</li>
|
||||
</router-link>
|
||||
@ -54,10 +52,8 @@
|
||||
>
|
||||
<li :class="{ 'is-active': isActive }">
|
||||
<a @click="navigate" @keypress.enter="navigate">
|
||||
<span class="icon is-small"
|
||||
><mdicon name="speaker" size="16"
|
||||
/></span>
|
||||
<span class="">Genres</span>
|
||||
<mdicon class="icon is-small" name="speaker" size="16" />
|
||||
<span v-text="$t('page.settings.tabs.music.genres')" />
|
||||
</a>
|
||||
</li>
|
||||
</router-link>
|
||||
@ -68,10 +64,12 @@
|
||||
>
|
||||
<li :class="{ 'is-active': isActive }">
|
||||
<a @click="navigate" @keypress.enter="navigate">
|
||||
<span class="icon is-small"
|
||||
><mdicon name="book-open-page-variant" size="16"
|
||||
/></span>
|
||||
<span class="">Composers</span>
|
||||
<mdicon
|
||||
class="icon is-small"
|
||||
name="book-open-page-variant"
|
||||
size="16"
|
||||
/>
|
||||
<span v-text="$t('page.settings.tabs.music.composers')" />
|
||||
</a>
|
||||
</li>
|
||||
</router-link>
|
||||
@ -83,10 +81,8 @@
|
||||
>
|
||||
<li :class="{ 'is-active': isActive }">
|
||||
<a @click="navigate" @keypress.enter="navigate">
|
||||
<span class="icon is-small"
|
||||
><mdicon name="spotify" size="16"
|
||||
/></span>
|
||||
<span class="">Spotify</span>
|
||||
<mdicon class="icon is-small" name="spotify" size="16" />
|
||||
<span v-text="$t('page.settings.tabs.music.spotify')" />
|
||||
</a>
|
||||
</li>
|
||||
</router-link>
|
||||
|
@ -11,10 +11,8 @@
|
||||
}"
|
||||
>
|
||||
<a @click="search_library">
|
||||
<span class="icon is-small"
|
||||
><mdicon name="bookshelf" size="16"
|
||||
/></span>
|
||||
<span class="">Library</span>
|
||||
<mdicon class="icon is-small" name="bookshelf" size="16" />
|
||||
<span v-text="$t('tabs.search.library')" />
|
||||
</a>
|
||||
</li>
|
||||
<li
|
||||
@ -23,10 +21,8 @@
|
||||
}"
|
||||
>
|
||||
<a @click="search_spotify">
|
||||
<span class="icon is-small"
|
||||
><mdicon name="spotify" size="16"
|
||||
/></span>
|
||||
<span class="">Spotify</span>
|
||||
<mdicon class="icon is-small" name="spotify" size="16" />
|
||||
<span v-text="$t('tabs.search.spotify')" />
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
@ -12,7 +12,7 @@
|
||||
>
|
||||
<li :class="{ 'is-active': isActive }">
|
||||
<a @click="navigate" @keypress.enter="navigate">
|
||||
<span class="">Webinterface</span>
|
||||
<span v-text="$t('page.settings.tabs.settings.general')" />
|
||||
</a>
|
||||
</li>
|
||||
</router-link>
|
||||
@ -23,7 +23,11 @@
|
||||
>
|
||||
<li :class="{ 'is-active': isActive }">
|
||||
<a @click="navigate" @keypress.enter="navigate">
|
||||
<span class="">Remotes & Outputs</span>
|
||||
<span
|
||||
v-text="
|
||||
$t('page.settings.tabs.settings.remotes-and-outputs')
|
||||
"
|
||||
/>
|
||||
</a>
|
||||
</li>
|
||||
</router-link>
|
||||
@ -34,7 +38,7 @@
|
||||
>
|
||||
<li :class="{ 'is-active': isActive }">
|
||||
<a @click="navigate" @keypress.enter="navigate">
|
||||
<span class="">Artwork</span>
|
||||
<span v-text="$t('page.settings.tabs.settings.artwork')" />
|
||||
</a>
|
||||
</li>
|
||||
</router-link>
|
||||
@ -45,7 +49,9 @@
|
||||
>
|
||||
<li :class="{ 'is-active': isActive }">
|
||||
<a @click="navigate" @keypress.enter="navigate">
|
||||
<span class="">Online Services</span>
|
||||
<span
|
||||
v-text="$t('page.settings.tabs.settings.online-services')"
|
||||
/>
|
||||
</a>
|
||||
</li>
|
||||
</router-link>
|
||||
@ -59,9 +65,7 @@
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'TabsSettings',
|
||||
|
||||
computed: {}
|
||||
name: 'TabsSettings'
|
||||
}
|
||||
</script>
|
||||
|
||||
|
15
web-src/src/i18n.js
Normal file
15
web-src/src/i18n.js
Normal file
@ -0,0 +1,15 @@
|
||||
import { createI18n } from 'vue-i18n'
|
||||
|
||||
/*
|
||||
* All i18n resources specified in the plugin `include` option can be loaded
|
||||
* at once using the import syntax.
|
||||
*/
|
||||
import messages from '@intlify/vite-plugin-vue-i18n/messages'
|
||||
|
||||
export default createI18n({
|
||||
legacy: false,
|
||||
globalInjection: true,
|
||||
locale: 'en',
|
||||
fallbackLocale: 'en',
|
||||
messages
|
||||
})
|
@ -2,9 +2,10 @@ import {
|
||||
mdiAccountMusic,
|
||||
mdiAlbum,
|
||||
mdiArrowCollapseDown,
|
||||
mdiBookOpenVariant,
|
||||
mdiBookOpenPageVariant,
|
||||
mdiBookOpenVariant,
|
||||
mdiBookshelf,
|
||||
mdiBroadcast,
|
||||
mdiCancel,
|
||||
mdiCast,
|
||||
mdiCastVariant,
|
||||
@ -26,16 +27,16 @@ import {
|
||||
mdiFolderOpen,
|
||||
mdiMagnify,
|
||||
mdiMenu,
|
||||
mdiMicrophone,
|
||||
mdiMusic,
|
||||
mdiMusicBoxMultiple,
|
||||
mdiOpenInNew,
|
||||
mdiPause,
|
||||
mdiPencil,
|
||||
mdiPipe,
|
||||
mdiPlay,
|
||||
mdiPlaylistPlay,
|
||||
mdiPlaylistPlus,
|
||||
mdiRadio,
|
||||
mdiPodcast,
|
||||
mdiRadioTower,
|
||||
mdiRefresh,
|
||||
mdiRepeat,
|
||||
@ -61,9 +62,10 @@ export const icons = {
|
||||
mdiAccountMusic,
|
||||
mdiAlbum,
|
||||
mdiArrowCollapseDown,
|
||||
mdiBookOpenVariant,
|
||||
mdiBookOpenPageVariant,
|
||||
mdiBookOpenVariant,
|
||||
mdiBookshelf,
|
||||
mdiBroadcast,
|
||||
mdiCancel,
|
||||
mdiCast,
|
||||
mdiCastVariant,
|
||||
@ -85,16 +87,16 @@ export const icons = {
|
||||
mdiFolderOpen,
|
||||
mdiMagnify,
|
||||
mdiMenu,
|
||||
mdiMicrophone,
|
||||
mdiMusic,
|
||||
mdiMusicBoxMultiple,
|
||||
mdiOpenInNew,
|
||||
mdiPause,
|
||||
mdiPencil,
|
||||
mdiPipe,
|
||||
mdiPlay,
|
||||
mdiPlaylistPlay,
|
||||
mdiPlaylistPlus,
|
||||
mdiRadio,
|
||||
mdiPodcast,
|
||||
mdiRadioTower,
|
||||
mdiRefresh,
|
||||
mdiRepeat,
|
||||
|
554
web-src/src/locales/en.json
Normal file
554
web-src/src/locales/en.json
Normal file
@ -0,0 +1,554 @@
|
||||
{
|
||||
"data": {
|
||||
"kind": {
|
||||
"file": "File",
|
||||
"url": "URL",
|
||||
"spotify": "Spotify",
|
||||
"pipe": "Stream"
|
||||
}
|
||||
},
|
||||
"dialog": {
|
||||
"cancel": "Cancel",
|
||||
"add": {
|
||||
"rss": {
|
||||
"add": "Add",
|
||||
"cancel": "Cancel",
|
||||
"help": "Adding a podcast includes creating an RSS playlist, that will allow OwnTone to manage the podcast subscription.",
|
||||
"placeholder": "https://url-to-rss",
|
||||
"processing": "Processing…",
|
||||
"title": "Add Podcast RSS feed URL"
|
||||
},
|
||||
"stream": {
|
||||
"add": "Add",
|
||||
"cancel": "Cancel",
|
||||
"loading": "Loading…",
|
||||
"placeholder": "https://url-to-stream",
|
||||
"play": "Play",
|
||||
"title": "Add Stream URL"
|
||||
}
|
||||
},
|
||||
"album": {
|
||||
"add-next": "Add Next",
|
||||
"add": "Add",
|
||||
"added-on": "Added on",
|
||||
"artist": "Album artist",
|
||||
"duration": "Duration",
|
||||
"mark-as-played": "Mark as played",
|
||||
"play": "Play",
|
||||
"release-date": "Release date",
|
||||
"remove-podcast": "Remove podcast",
|
||||
"tracks": "Track count",
|
||||
"type": "Type",
|
||||
"year": "Year"
|
||||
},
|
||||
"artist": {
|
||||
"add-next": "Add Next",
|
||||
"add": "Add",
|
||||
"added-on": "Added On",
|
||||
"albums": "Albums",
|
||||
"play": "Play",
|
||||
"tracks": "Tracks",
|
||||
"type": "Type"
|
||||
},
|
||||
"composer": {
|
||||
"add-next": "Add Next",
|
||||
"add": "Add",
|
||||
"albums": "Albums",
|
||||
"duration": "Duration",
|
||||
"play": "Play",
|
||||
"tracks": "Tracks"
|
||||
},
|
||||
"directory": {
|
||||
"add-next": "Add Next",
|
||||
"add": "Add",
|
||||
"play": "Play"
|
||||
},
|
||||
"genre": {
|
||||
"add-next": "Add Next",
|
||||
"add": "Add",
|
||||
"albums": "Albums",
|
||||
"duration": "Duration",
|
||||
"play": "Play",
|
||||
"tracks": "Tracks"
|
||||
},
|
||||
"playlist": {
|
||||
"add-next": "Add Next",
|
||||
"add": "Add",
|
||||
"play": "Play",
|
||||
"track-count": "Track Count",
|
||||
"type": "Type",
|
||||
"save": {
|
||||
"cancel": "Cancel",
|
||||
"save": "Save",
|
||||
"saving": "Saving…",
|
||||
"title": "Save queue to playlist"
|
||||
}
|
||||
},
|
||||
"queue-item": {
|
||||
"album-artist": "Album Artist",
|
||||
"album": "Album",
|
||||
"bitrate": "{'|'} {rate} kbit/s",
|
||||
"channels": "{'|'} {channels}",
|
||||
"composer": "Composer",
|
||||
"duration": "Duration",
|
||||
"genre": "Genre",
|
||||
"path": "Path",
|
||||
"play": "Play",
|
||||
"position": "Disc / Track",
|
||||
"quality": "Quality",
|
||||
"remove": "Remove",
|
||||
"samplerate": "{'|'} {rate} Hz",
|
||||
"spotify-album": "album",
|
||||
"spotify-artist": "artist",
|
||||
"type": "Type",
|
||||
"year": "Year"
|
||||
},
|
||||
"remote-pairing": {
|
||||
"cancel": "Cancel",
|
||||
"pair": "Pair Remote",
|
||||
"title": "Remote pairing request"
|
||||
},
|
||||
"spotify": {
|
||||
"album": {
|
||||
"add-next": "Add Next",
|
||||
"add": "Add",
|
||||
"album-artist": "Album Artist",
|
||||
"play": "Play",
|
||||
"release-date": "Release Date",
|
||||
"type": "Type"
|
||||
},
|
||||
"artist": {
|
||||
"add-next": "Add Next",
|
||||
"add": "Add",
|
||||
"genres": "Genres",
|
||||
"play": "Play",
|
||||
"popularity": "Popularity / Followers"
|
||||
},
|
||||
"playlist": {
|
||||
"add-next": "Add Next",
|
||||
"add": "Add",
|
||||
"owner": "Owner",
|
||||
"path": "Path",
|
||||
"play": "Play",
|
||||
"tracks": "Tracks"
|
||||
},
|
||||
"track": {
|
||||
"add-next": "Add Next",
|
||||
"add": "Add",
|
||||
"album-artist": "Album Artist",
|
||||
"album": "Album",
|
||||
"duration": "Duration",
|
||||
"path": "Path",
|
||||
"play": "Play",
|
||||
"position": "Disc / Track",
|
||||
"release-date": "Release Date"
|
||||
}
|
||||
},
|
||||
"track": {
|
||||
"add-next": "Add Next",
|
||||
"add": "Add",
|
||||
"added-on": "Added On",
|
||||
"album-artist": "Album Artist",
|
||||
"album": "Album",
|
||||
"bitrate": " {'|'} {rate} Kb/s",
|
||||
"channels": " {'|'} {channels}",
|
||||
"comment": "Comment",
|
||||
"composer": "Composer",
|
||||
"duration": "Duration",
|
||||
"genre": "Genre",
|
||||
"mark-as-new": "Mark as new",
|
||||
"mark-as-played": "Mark as played",
|
||||
"path": "Path",
|
||||
"play": "Play",
|
||||
"position": "Disc / Track",
|
||||
"quality": "Quality",
|
||||
"rating-value": "{rating} / 10",
|
||||
"rating": "Rating",
|
||||
"release-date": "Release Date",
|
||||
"samplerate": " {'|'} {rate} Hz",
|
||||
"spotify-album": "album",
|
||||
"spotify-artist": "artist",
|
||||
"type": "Type",
|
||||
"year": "Year"
|
||||
},
|
||||
"update": {
|
||||
"all": "Update everything",
|
||||
"cancel": "Cancel",
|
||||
"feeds": "Only update RSS feeds",
|
||||
"info": "Scan for new, deleted and modified files",
|
||||
"local": "Only update local library",
|
||||
"progress": "Library update in progress…",
|
||||
"rescan-metadata": "Rescan metadata of unmodified files",
|
||||
"rescan": "Rescan",
|
||||
"spotify": "Only update Spotify",
|
||||
"title": "Library update"
|
||||
}
|
||||
},
|
||||
"language": {
|
||||
"en": "English",
|
||||
"fr": "French (Français)"
|
||||
},
|
||||
"list": {
|
||||
"albums": {
|
||||
"info-1": "Permanently remove this podcast from your library?",
|
||||
"info-2": "This will also remove the RSS playlist ",
|
||||
"notification": "Podcast cannot be removed. Probably it was not added as an RSS playlist."
|
||||
},
|
||||
"spotify": {
|
||||
"not-playable-track": "Track is not playable",
|
||||
"restriction-reason": ", restriction reason: {reason}"
|
||||
}
|
||||
},
|
||||
"media": {
|
||||
"kind": {
|
||||
"album": "Album",
|
||||
"audiobook": "Audiobook",
|
||||
"music": "Music",
|
||||
"podcast": "Podcast"
|
||||
}
|
||||
},
|
||||
"navigation": {
|
||||
"about": "About",
|
||||
"albums": "Albums",
|
||||
"artists": "Artists",
|
||||
"audiobooks": "Audiobooks",
|
||||
"now-playing": " - {album}",
|
||||
"stream-error": "HTTP stream error: failed to load stream or stopped loading due to network problem",
|
||||
"stream": "HTTP stream",
|
||||
"volume": "Volume",
|
||||
"files": "Files",
|
||||
"genres": "Genres",
|
||||
"music": "Music",
|
||||
"playlists": "Playlists",
|
||||
"podcasts": "Podcasts",
|
||||
"radio": "Radio",
|
||||
"search": "Search",
|
||||
"settings": "Settings",
|
||||
"spotify": "Spotify",
|
||||
"title": "OwnTone",
|
||||
"update-library": "Update Library"
|
||||
},
|
||||
"page": {
|
||||
"about": {
|
||||
"albums": "Albums",
|
||||
"artists": "Artists",
|
||||
"built-with": "Web interface built with <a href=\"https://bulma.io\">Bulma</a>, <a href=\"https://materialdesignicons.com/\">Material Design Icons</a>, <a href=\"https://vuejs.org/\">Vue.js</a>, <a href=\"https://github.com/mzabriskie/axios\">axios</a> and <a href=\"https://github.com/owntone/owntone-server/network/dependencies\">more</a>.",
|
||||
"compiled-with": "Compiled with support for {options}.",
|
||||
"library": "Library",
|
||||
"total-playtime": "Total playtime",
|
||||
"tracks": "Tracks",
|
||||
"update": "Update",
|
||||
"updated-on": "{time} ago",
|
||||
"updated": "Updated",
|
||||
"uptime": "Uptime",
|
||||
"version": "Version {version}"
|
||||
},
|
||||
"album": {
|
||||
"shuffle": "Shuffle",
|
||||
"track-count": "{count} tracks"
|
||||
},
|
||||
"albums": {
|
||||
"count": "{count} albums",
|
||||
"filter": "Filter",
|
||||
"hide-singles-help": "If active, hides singles and albums with tracks that only appear in playlists.",
|
||||
"hide-singles": "Hide singles",
|
||||
"hide-spotify-help": "If active, hides albums that only appear in your Spotify library.",
|
||||
"hide-spotify": "Hide albums from Spotify",
|
||||
"title": "Albums",
|
||||
"sort-by": {
|
||||
"title": "Sort by",
|
||||
"name": "Name",
|
||||
"recently-added": "Recently added",
|
||||
"recently-released": "Recently released"
|
||||
}
|
||||
},
|
||||
"artist": {
|
||||
"album-count": "{count} albums {'|'} ",
|
||||
"shuffle": "Shuffle",
|
||||
"track-count": "{count} tracks",
|
||||
"sort-by": {
|
||||
"title": "Sort by",
|
||||
"name": "Name",
|
||||
"release-date": "Release date"
|
||||
}
|
||||
},
|
||||
"artists": {
|
||||
"count": "{count} artists",
|
||||
"filter": "Filter",
|
||||
"sort-by": {
|
||||
"title": "Sort by",
|
||||
"name": "Name",
|
||||
"recently-added": "Rencently added"
|
||||
},
|
||||
"hide-singles-help": "If active, hides artists that only appear on singles or playlists.",
|
||||
"hide-singles": "Hide singles",
|
||||
"hide-spotify-help": "If active, hides artists that only appear in your Spotify library.",
|
||||
"hide-spotify": "Hide artists from Spotify",
|
||||
"title": "Artists"
|
||||
},
|
||||
"audiobooks": {
|
||||
"album": {
|
||||
"play": "Play",
|
||||
"track-count": "{count} tracks"
|
||||
},
|
||||
"albums": {
|
||||
"count": "{count} audiobooks",
|
||||
"title": "Audiobooks"
|
||||
},
|
||||
"artist": {
|
||||
"albums-count": "{count} albums",
|
||||
"shuffle": "Shuffle"
|
||||
},
|
||||
"artists": {
|
||||
"count": "{count} authors",
|
||||
"title": "Authors"
|
||||
}
|
||||
},
|
||||
"browse": {
|
||||
"albums": "albums",
|
||||
"show-more": "Show more",
|
||||
"tracks": "tracks",
|
||||
"recently-added": {
|
||||
"albums": "albums",
|
||||
"title": "Recently added"
|
||||
},
|
||||
"recently-played": {
|
||||
"title": "Recently played",
|
||||
"tracks": "tracks"
|
||||
}
|
||||
},
|
||||
"composer": {
|
||||
"album-count": "{count} albums {'|'}",
|
||||
"shuffle": "Shuffle",
|
||||
"track-count": "{count} tracks",
|
||||
"tracks": {
|
||||
"album-count": "{count} albums",
|
||||
"track-count": " {'|'} {count} tracks",
|
||||
"shuffle": "Shuffle"
|
||||
}
|
||||
},
|
||||
"composers": {
|
||||
"count": "{count} composers",
|
||||
"title": "Composers"
|
||||
},
|
||||
"files": {
|
||||
"play": "Play",
|
||||
"title": "Files"
|
||||
},
|
||||
"genre": {
|
||||
"album-count": "{count} albums {'|'} ",
|
||||
"shuffle": "Shuffle",
|
||||
"tracks": {
|
||||
"album-count": "{count} albums {'|'} ",
|
||||
"count": " {count} tracks",
|
||||
"shuffle": "Shuffle"
|
||||
}
|
||||
},
|
||||
"genres": {
|
||||
"count": "{count} genres",
|
||||
"title": "Genres"
|
||||
},
|
||||
"now-playing": {
|
||||
"info": "Add some tracks by browsing your library",
|
||||
"title": "Your play queue is empty"
|
||||
},
|
||||
"playlist": {
|
||||
"length": "{length} tracks",
|
||||
"shuffle": "Shuffle"
|
||||
},
|
||||
"playlists": {
|
||||
"count": "{count} playlists"
|
||||
},
|
||||
"podcast": {
|
||||
"play": "Play",
|
||||
"remove-error": "Podcast cannot be removed. Probably it was not added as an RSS playlist.",
|
||||
"remove-info-1": "Permanently remove this podcast from your library?",
|
||||
"remove-info-2": "This will also remove the RSS playlist ",
|
||||
"track-count": "{count} tracks"
|
||||
},
|
||||
"podcasts": {
|
||||
"add": "Add",
|
||||
"count": "{count} podcasts",
|
||||
"mark-all-played": "Mark All Played",
|
||||
"new-episodes": "New Episodes",
|
||||
"title": "Podcasts",
|
||||
"update": "Update"
|
||||
},
|
||||
"queue": {
|
||||
"add-stream": "Add stream",
|
||||
"clear": "Clear",
|
||||
"count": "{count} tracks",
|
||||
"edit": "Edit",
|
||||
"hide-previous": "Hide previous",
|
||||
"title": "Queue"
|
||||
},
|
||||
"radio": {
|
||||
"count": "{count} stations",
|
||||
"title": "Radio"
|
||||
},
|
||||
"search": {
|
||||
"albums": "Albums",
|
||||
"artists": "Artists",
|
||||
"audiobooks": "Audiobooks",
|
||||
"composers": "Composers",
|
||||
"help": "Tip: you can search by a smart playlist query language <a href=\"https://github.com/owntone/owntone-server/blob/master/README_SMARTPL.md\" target=\"_blank\">expression</a> if you prefix it with <code>query:</code>.",
|
||||
"no-albums": "No albums found",
|
||||
"no-artists": "No artists found",
|
||||
"no-audiobooks": "No audiobooks found",
|
||||
"no-composers": "No composers found",
|
||||
"no-playlists": "No playlists found",
|
||||
"no-podcasts": "No podcasts found",
|
||||
"no-tracks": "No tracks found",
|
||||
"playlists": "Playlists",
|
||||
"podcasts": "Podcasts",
|
||||
"show-albums": "Show all {count} albums",
|
||||
"show-artists": "Show all {count} artists",
|
||||
"show-audiobooks": "Show all {count} audiobooks",
|
||||
"show-composers": "Show all {count} composers",
|
||||
"show-playlists": "Show all {count} playlists",
|
||||
"show-podcasts": "Show all {count} podcasts",
|
||||
"show-tracks": "Show all {count} tracks",
|
||||
"tracks": "Tracks"
|
||||
},
|
||||
"settings": {
|
||||
"artwork": {
|
||||
"artwork": "Artwork",
|
||||
"coverartarchive": "Cover Art Archive",
|
||||
"discogs": "Discogs",
|
||||
"explanation-1": "OwnTone 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.",
|
||||
"explanation-2": "In addition to that, you can enable fetching artwork from the following artwork providers:",
|
||||
"spotify": "Spotify"
|
||||
},
|
||||
"devices": {
|
||||
"no-active-pairing": "No active pairing request.",
|
||||
"pairing-request": "Remote pairing request from ",
|
||||
"pairing": "Remote Pairing",
|
||||
"send": "Send",
|
||||
"speaker-pairing-info": "If your speaker requires pairing then activate it below and enter the PIN that it displays.",
|
||||
"speaker-pairing": "Speaker pairing and device verification",
|
||||
"verification-code": "Enter verification code",
|
||||
"verify": "Verify"
|
||||
},
|
||||
"general": {
|
||||
"album-lists": "Album Lists",
|
||||
"audiobooks": "Audiobooks",
|
||||
"files": "Audio Files",
|
||||
"language": "Language",
|
||||
"music": "Music",
|
||||
"navigation-item-selection-info": "If you select more items than can be shown on your screen then the burger menu will disappear.",
|
||||
"navigation-item-selection": "Select the top navigation bar menu items",
|
||||
"navigation-items": "Navigation Bar",
|
||||
"now-playing-page": "Now playing page",
|
||||
"playlists": "Playlists",
|
||||
"podcasts": "Podcasts",
|
||||
"radio": "Radio",
|
||||
"recently-added-page-info": "Limit the number of albums shown on the \"Recently Added\" page",
|
||||
"recently-added-page": "Recently added page",
|
||||
"search": "Search",
|
||||
"show-composer-genres-info-1": "Comma separated list of genres the composer should be displayed on the \"now playing page\"",
|
||||
"show-composer-genres-info-2": "Leave empty to always show the composer.",
|
||||
"show-composer-genres-info-3": "The genre tag of the current track is matched by checking, if one of the defined genres are included. For example setting to \"classical, soundtrack\" will show the composer for tracks with a genre tag of \"Contemporary Classical\"",
|
||||
"show-composer-genres": "Show composer only for listed genres",
|
||||
"show-composer-info": "If enabled the composer of the current playing track is shown on the \"now playing page\"",
|
||||
"show-composer": "Show composer",
|
||||
"show-coverart": "Show cover artwork in album list"
|
||||
},
|
||||
"services": {
|
||||
"lastfm": {
|
||||
"grant-access": "<b>Last.fm</b> - Login with your Last.fm username and password to enable scrobbling",
|
||||
"info": "OwnTone will not store your Last.fm username/password, only the session key. The session key does not expire.",
|
||||
"title": "Last.fm",
|
||||
"no-support": "OwnTone was built without support for Last.fm.",
|
||||
"stop-scrobbling": "Stop scrobbling"
|
||||
},
|
||||
"spotify": {
|
||||
"no-support": "OwnTone was either built without support for Spotify or libspotify is not installed.",
|
||||
"help": "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.",
|
||||
"logged-as": "Logged in as ",
|
||||
"requirements": "You must have a Spotify premium account.",
|
||||
"scopes": "Access to the Spotify Web API enables scanning of your Spotify library. Required scopes are: ",
|
||||
"user": "Access granted for ",
|
||||
"authorize": "Authorize Web API access",
|
||||
"credentials": " - Login with your Spotify username and password",
|
||||
"grant-access": "<b>Spotify Web API</b> - Grant access to the Spotify Web API",
|
||||
"help-1": "libspotify enables OwnTone to play Spotify tracks.",
|
||||
"help-2": "OwnTone will not store your password, but will still be able to log you in automatically afterwards, because libspotify saves a login token.",
|
||||
"reauthorize": "Please reauthorize Web API access to grant OwnTone the following additional access rights: ",
|
||||
"title": "Spotify"
|
||||
},
|
||||
"login": "Login",
|
||||
"logout": "Logout"
|
||||
},
|
||||
"tabs": {
|
||||
"music": {
|
||||
"albums": "Albums",
|
||||
"artists": "Artists",
|
||||
"browse": "Browse",
|
||||
"composers": "Composers",
|
||||
"genres": "Genres",
|
||||
"spotify": "Spotify"
|
||||
},
|
||||
"search": {
|
||||
"library": "Library",
|
||||
"spotify": "Spotify"
|
||||
},
|
||||
"settings": {
|
||||
"artwork": "Artwork",
|
||||
"general": "General",
|
||||
"online-services": "Online Services",
|
||||
"remotes-and-outputs": "Remotes and Outputs"
|
||||
}
|
||||
}
|
||||
},
|
||||
"spotify": {
|
||||
"album": {
|
||||
"shuffle": "Shuffle",
|
||||
"track-count": "{count} tracks"
|
||||
},
|
||||
"artist": {
|
||||
"album-count": "{count} albums",
|
||||
"shuffle": "Shuffle"
|
||||
},
|
||||
"browse": {
|
||||
"featured-playlists": "Featured Playlists",
|
||||
"new-releases": "New Releases",
|
||||
"show-more": "Show More"
|
||||
},
|
||||
"playlist": {
|
||||
"count": "{count} tracks",
|
||||
"shuffle": "Shuffle"
|
||||
},
|
||||
"search": {
|
||||
"albums": "Albums",
|
||||
"artists": "Artists",
|
||||
"no-albums": "No albums found",
|
||||
"no-artists": "No artists found",
|
||||
"no-playlists": "No playlists found",
|
||||
"no-tracks": "No tracks found",
|
||||
"playlists": "Playlists",
|
||||
"show-all-albums": "Show all {count} albums",
|
||||
"show-all-artists": "Show all {count} artists",
|
||||
"show-all-playlists": "Show all {count} playlists",
|
||||
"show-all-tracks": "Show all {count} tracks",
|
||||
"tracks": "Tracks"
|
||||
}
|
||||
}
|
||||
},
|
||||
"setting": {
|
||||
"not-saved": " (error saving setting)",
|
||||
"saved": " (setting saved)"
|
||||
},
|
||||
"server": {
|
||||
"connection-failed": "Failed to connect to OwnTone server",
|
||||
"missing-port": "Missing websocket port",
|
||||
"request-failed": "Request failed (status: {status} {cause} {url})",
|
||||
"queue-saved": "Queue saved to playlist {name}",
|
||||
"appended-tracks": "{count} tracks appended to the queue",
|
||||
"empty-queue": "Queue is empty"
|
||||
},
|
||||
"group-by-list": {
|
||||
"today": "Today",
|
||||
"last-week": "Last week",
|
||||
"last-month": "Last month"
|
||||
}
|
||||
}
|
554
web-src/src/locales/fr.json
Normal file
554
web-src/src/locales/fr.json
Normal file
@ -0,0 +1,554 @@
|
||||
{
|
||||
"data": {
|
||||
"kind": {
|
||||
"file": "Fichier",
|
||||
"url": "URL",
|
||||
"spotify": "Spotify",
|
||||
"pipe": "Flux"
|
||||
}
|
||||
},
|
||||
"dialog": {
|
||||
"cancel": "Annuler",
|
||||
"add": {
|
||||
"rss": {
|
||||
"add": "Ajouter",
|
||||
"cancel": "Annuler",
|
||||
"help": "L’ajout d’un podcast inclut la création d’une liste de lecture RSS, qui permettra à OwnTone de gérer l’abonnement au podcast.",
|
||||
"placeholder": "https://url-du-flux-rss",
|
||||
"processing": "Traitement en cours…",
|
||||
"title": "Ajouter l’URL du flux RSS du podcast"
|
||||
},
|
||||
"stream": {
|
||||
"add": "Ajouter",
|
||||
"cancel": "Annuler",
|
||||
"loading": "Chargement…",
|
||||
"placeholder": "https://url-du-flux",
|
||||
"play": "Lire",
|
||||
"title": "Ajouter l’URL du flux"
|
||||
}
|
||||
},
|
||||
"album": {
|
||||
"add-next": "Ajouter ensuite",
|
||||
"add": "Ajouter",
|
||||
"added-on": "Ajouté le",
|
||||
"artiste": "Album artist",
|
||||
"duration": "Durée",
|
||||
"mark-as-played": "Marquer comme lu",
|
||||
"play": "Lire",
|
||||
"release-date": "Date de sortie",
|
||||
"remove-podcast": "Supprimer le podcast",
|
||||
"pistes": "Pistes",
|
||||
"type": "Type",
|
||||
"year": "Année"
|
||||
},
|
||||
"artiste": {
|
||||
"add-next": "Ajouter ensuite",
|
||||
"add": "Ajouter",
|
||||
"added-on": "Ajouté le",
|
||||
"albums": "Albums",
|
||||
"play": "Lire",
|
||||
"pistes": "Pistes",
|
||||
"type": "Type"
|
||||
},
|
||||
"composer": {
|
||||
"add-next": "Ajouter ensuite",
|
||||
"add": "Ajouter",
|
||||
"albums": "Albums",
|
||||
"duration": "Durée",
|
||||
"play": "Lire",
|
||||
"pistes": "Pistes"
|
||||
},
|
||||
"directory": {
|
||||
"add-next": "Ajouter ensuite",
|
||||
"add": "Ajouter",
|
||||
"play": "Lire"
|
||||
},
|
||||
"genre": {
|
||||
"add-next": "Ajouter ensuite",
|
||||
"add": "Ajouter",
|
||||
"albums": "Albums",
|
||||
"duration": "Durée",
|
||||
"play": "Lire",
|
||||
"pistes": "Pistes"
|
||||
},
|
||||
"playlist": {
|
||||
"add-next": "Ajouter ensuite",
|
||||
"add": "Ajouter",
|
||||
"play": "Lire",
|
||||
"track-count": "Pistes",
|
||||
"type": "Type",
|
||||
"save": {
|
||||
"cancel": "Annuler",
|
||||
"save": "Enregistrer",
|
||||
"saving": "Enregistrement en cours…",
|
||||
"title": "Enregister la file d’attente dans une liste de lecture"
|
||||
}
|
||||
},
|
||||
"queue-item": {
|
||||
"album-artist": "Artiste de l’album",
|
||||
"album": "Album",
|
||||
"bitrate": "{'|'} {rate} kbit/s",
|
||||
"channels": "{'|'} {channels}",
|
||||
"composer": "Compositeur",
|
||||
"duration": "Durée",
|
||||
"genre": "Genre",
|
||||
"path": "Emplacement",
|
||||
"play": "Lire",
|
||||
"position": "Disque / Piste",
|
||||
"quality": "Qualité",
|
||||
"remove": "Supprimer",
|
||||
"samplerate": "{'|'} {rate} Hz",
|
||||
"spotify-album": "album",
|
||||
"spotify-artist": "artiste",
|
||||
"type": "Type",
|
||||
"year": "Année"
|
||||
},
|
||||
"remote-pairing": {
|
||||
"cancel": "Annuler",
|
||||
"pair": "Jumeler la télécommande",
|
||||
"title": "Demande de jumelage de télécommande"
|
||||
},
|
||||
"spotify": {
|
||||
"album": {
|
||||
"add-next": "Ajouter ensuite",
|
||||
"add": "Ajouter",
|
||||
"album-artist": "Artiste de l’album",
|
||||
"play": "Lire",
|
||||
"release-date": "Date de sortie",
|
||||
"type": "Type"
|
||||
},
|
||||
"artiste": {
|
||||
"add-next": "Ajouter ensuite",
|
||||
"add": "Ajouter",
|
||||
"genres": "Genres",
|
||||
"play": "Lire",
|
||||
"popularity": "Popularités / Followers"
|
||||
},
|
||||
"playlist": {
|
||||
"add-next": "Ajouter ensuite",
|
||||
"add": "Ajouter",
|
||||
"owner": "Propriéataire",
|
||||
"path": "Emplacement",
|
||||
"play": "Lire",
|
||||
"pistes": "Pistes"
|
||||
},
|
||||
"track": {
|
||||
"add-next": "Ajouter ensuite",
|
||||
"add": "Ajouter",
|
||||
"album-artist": "Artiste de l’album",
|
||||
"album": "Album",
|
||||
"duration": "Durée",
|
||||
"path": "Emplacement",
|
||||
"play": "Lire",
|
||||
"position": "Disque / Piste",
|
||||
"release-date": "Date de sortie"
|
||||
}
|
||||
},
|
||||
"track": {
|
||||
"add-next": "Ajouter ensuite",
|
||||
"add": "Ajouter",
|
||||
"added-on": "Ajouté le",
|
||||
"album-artist": "Artiste de l’album",
|
||||
"album": "Album",
|
||||
"bitrate": " {'|'} {rate} Kb/s",
|
||||
"channels": " {'|'} {channels}",
|
||||
"comment": "Commentaire",
|
||||
"composer": "Compositeur",
|
||||
"duration": "Durée",
|
||||
"genre": "Genre",
|
||||
"mark-as-new": "Marquer comme nouveau",
|
||||
"mark-as-played": "Marquer comme lu",
|
||||
"path": "Emplacement",
|
||||
"play": "Lire",
|
||||
"position": "Disque / Piste",
|
||||
"quality": "Qualité",
|
||||
"rating-value": "{rating} / 10",
|
||||
"rating": "Classement",
|
||||
"release-date": "Date de sortie",
|
||||
"samplerate": " {'|'} {rate} Hz",
|
||||
"spotify-album": "album",
|
||||
"spotify-artist": "artiste",
|
||||
"type": "Type",
|
||||
"year": "Année"
|
||||
},
|
||||
"update": {
|
||||
"all": "Tout actualiser",
|
||||
"cancel": "Annuler",
|
||||
"feeds": "Actualiser uniquement les flux RSS",
|
||||
"info": "Recherche les fichiers ajoutés, supprimés et modifiés",
|
||||
"local": "Actualiser uniquement la bibliothèque locale",
|
||||
"progress": "Actualisation de la bibliothèque en cours…",
|
||||
"rescan-metadata": "Analyser les métadonnées des fichiers non modifiés",
|
||||
"rescan": "Analyser",
|
||||
"spotify": "Actualiser uniquement Spotify",
|
||||
"title": "Actualisation de la bibliothèque"
|
||||
}
|
||||
},
|
||||
"language": {
|
||||
"en": "Anglais (English)",
|
||||
"fr": "Français"
|
||||
},
|
||||
"list": {
|
||||
"albums": {
|
||||
"info-1": "Supprimer définitivement ce podcast de votre bibliothèque ?",
|
||||
"info-2": "Cela supprimera également la liste de lecture RSS ",
|
||||
"notification": "Le podcast ne peut être supprimé. Il n’avait probablement pas été ajouté comme une liste de lecture RSS."
|
||||
},
|
||||
"spotify": {
|
||||
"not-playable-track": "La piste ne peut pas être lue",
|
||||
"restriction-reason": ", raison de la restriction : {reason}"
|
||||
}
|
||||
},
|
||||
"media": {
|
||||
"kind": {
|
||||
"album": "Album",
|
||||
"audiobook": "Livre audio",
|
||||
"music": "Musique",
|
||||
"podcast": "Podcast"
|
||||
}
|
||||
},
|
||||
"navigation": {
|
||||
"about": "À propos",
|
||||
"albums": "Albums",
|
||||
"artists": "Artistes",
|
||||
"audiobooks": "Livres audio",
|
||||
"now-playing": " - {album}",
|
||||
"stream-error": "Erreur du flux HTTP : échec du chargement du flux ou arrêt du chargement en raison d’un problème réseau",
|
||||
"stream": "Flux HTTP",
|
||||
"volume": "Volume",
|
||||
"files": "Fichiers",
|
||||
"genres": "Genres",
|
||||
"music": "Musique",
|
||||
"playlists": "Listes de lecture",
|
||||
"podcasts": "Podcasts",
|
||||
"radio": "Radio",
|
||||
"search": "Recherche",
|
||||
"settings": "Réglages",
|
||||
"spotify": "Spotify",
|
||||
"title": "OwnTone",
|
||||
"update-library": "Actualiser la bibliothèque"
|
||||
},
|
||||
"page": {
|
||||
"about": {
|
||||
"albums": "Albums",
|
||||
"artists": "Artistes",
|
||||
"built-with": "Interface utilisateur construite avec <a href=\"https://bulma.io\">Bulma</a>, <a href=\"https://materialdesignicons.com/\">Material Design Icons</a>, <a href=\"https://vuejs.org/\">Vue.js</a>, <a href=\"https://github.com/mzabriskie/axios\">axios</a> et <a href=\"https://github.com/owntone/owntone-server/network/dependencies\">plus</a>.",
|
||||
"compiled-with": "Compilé avec les options {options}.",
|
||||
"library": "Bibliothèque",
|
||||
"total-playtime": "Durée totale de lecture",
|
||||
"pistes": "Pistes",
|
||||
"update": "Actualiser",
|
||||
"updated-on": "il y a {time}",
|
||||
"updated": "Mis à jour",
|
||||
"uptime": "Temps de fonctionnement",
|
||||
"name": "Version {version}"
|
||||
},
|
||||
"album": {
|
||||
"shuffle": "Lecture aléatoire",
|
||||
"track-count": "{count} pistes"
|
||||
},
|
||||
"albums": {
|
||||
"count": "{count} albums",
|
||||
"filter": "Filtre",
|
||||
"hide-singles-help": "Si actif, masque les singles et les albums dont les pistes n’apparaissent que dans les listes de lecture.",
|
||||
"hide-singles": "Masquer les singles",
|
||||
"hide-spotify-help": "Si actif, masque les albums qui n’apparaissent que dans votre bibliothèque Spotify.",
|
||||
"hide-spotify": "Masquer les albums de Spotify",
|
||||
"title": "Albums",
|
||||
"sort-by": {
|
||||
"title": "Trier par",
|
||||
"name": "Nom",
|
||||
"recently-added": "Ajouts récents",
|
||||
"recently-released": "Sorties récentes"
|
||||
}
|
||||
},
|
||||
"artist": {
|
||||
"album-count": "{count} albums {'|'} ",
|
||||
"shuffle": "Lecture aléatoire",
|
||||
"track-count": "{count} pistes",
|
||||
"sort-by": {
|
||||
"title": "Trier par",
|
||||
"name": "Nom",
|
||||
"release-date": "Date de sortie"
|
||||
}
|
||||
},
|
||||
"artists": {
|
||||
"count": "{count} artists",
|
||||
"filter": "Filtre",
|
||||
"sort-by": {
|
||||
"title": "Trier par",
|
||||
"name": "Nom",
|
||||
"recently-added": "Ajouts récents"
|
||||
},
|
||||
"hide-singles-help": "Si actif, masque les artistes qui n’apparaissent que dans des singles ou des listes de lecture.",
|
||||
"hide-singles": "Masquer les singles",
|
||||
"hide-spotify-help": "Si actif, masque les artistes qui n’apparaissent que dans votre bibliothèque Spotify.",
|
||||
"hide-spotify": "Masquer les artistes de Spotify",
|
||||
"title": "Artistes"
|
||||
},
|
||||
"audiobooks": {
|
||||
"album": {
|
||||
"play": "Lire",
|
||||
"track-count": "{count} pistes"
|
||||
},
|
||||
"albums": {
|
||||
"count": "{count} livres audio",
|
||||
"title": "Livres audio"
|
||||
},
|
||||
"artiste": {
|
||||
"albums-count": "{count} albums",
|
||||
"shuffle": "Lecture aléatoire"
|
||||
},
|
||||
"artists": {
|
||||
"count": "{count} auteurs",
|
||||
"title": "Auteurs"
|
||||
}
|
||||
},
|
||||
"browse": {
|
||||
"albums": "albums",
|
||||
"show-more": "Afficher plus",
|
||||
"pistes": "pistes",
|
||||
"recently-added": {
|
||||
"albums": "albums",
|
||||
"title": "Ajouts récents"
|
||||
},
|
||||
"recently-played": {
|
||||
"title": "Lectures récentes",
|
||||
"pistes": "pistes"
|
||||
}
|
||||
},
|
||||
"composer": {
|
||||
"album-count": "{count} albums {'|'}",
|
||||
"shuffle": "Lecture aléatoire",
|
||||
"track-count": "{count} pistes",
|
||||
"pistes": {
|
||||
"album-count": "{count} albums",
|
||||
"track-count": " {'|'} {count} pistes",
|
||||
"shuffle": "Lecture aléatoire"
|
||||
}
|
||||
},
|
||||
"composers": {
|
||||
"count": "{count} compositeurs",
|
||||
"title": "Compositeurs"
|
||||
},
|
||||
"files": {
|
||||
"play": "Lire",
|
||||
"title": "Fichiers"
|
||||
},
|
||||
"genre": {
|
||||
"album-count": "{count} albums {'|'} ",
|
||||
"shuffle": "Lecture aléatoire",
|
||||
"pistes": {
|
||||
"album-count": "{count} albums {'|'} ",
|
||||
"count": " {count} pistes",
|
||||
"shuffle": "Lecture aléatoire"
|
||||
}
|
||||
},
|
||||
"genres": {
|
||||
"count": "{count} genres",
|
||||
"title": "Genres"
|
||||
},
|
||||
"now-playing": {
|
||||
"info": "Ajoutez des pistes en parcourant votre bibliothèque",
|
||||
"title": "La file d’attente est vide"
|
||||
},
|
||||
"playlist": {
|
||||
"length": "{length} pistes",
|
||||
"shuffle": "Lecture aléatoire"
|
||||
},
|
||||
"playlists": {
|
||||
"count": "{count} listes de lecture"
|
||||
},
|
||||
"podcast": {
|
||||
"play": "Lire",
|
||||
"remove-error": "Le podcast ne peut pas être supprimé. Il n’a probablement pas été ajouté en tant que liste de lecture RSS.",
|
||||
"remove-info-1": "Supprimer ce podcast de manière permanente de la bibliothèque ?",
|
||||
"remove-info-2": "Cela supprimera également la liste de lecture RSS ",
|
||||
"track-count": "{count} pistes"
|
||||
},
|
||||
"podcasts": {
|
||||
"add": "Ajouter",
|
||||
"count": "{count} podcasts",
|
||||
"mark-all-played": "Marquer comme lus",
|
||||
"new-episodes": "Nouveaux épisodes",
|
||||
"title": "Podcasts",
|
||||
"update": "Actualiser"
|
||||
},
|
||||
"queue": {
|
||||
"add-stream": "Ajouter un flux",
|
||||
"clear": "Effacer",
|
||||
"count": "{count} pistes",
|
||||
"edit": "Éditer",
|
||||
"hide-previous": "Masquer l’historique",
|
||||
"queue": "File d’attente"
|
||||
},
|
||||
"radio": {
|
||||
"count": "{count} stations",
|
||||
"title": "Radio"
|
||||
},
|
||||
"search": {
|
||||
"albums": "Albums",
|
||||
"artists": "Artistes",
|
||||
"audiobooks": "Livres audio",
|
||||
"composers": "Compositeurs",
|
||||
"help": "Astuce : en préfixant votre requête avec <code>query:</code>, vous pouvez effectuer une recherche avec une <a href=\"https://github.com/owntone/owntone-server/blob/master/README_SMARTPL.md\" target=\"_blank\">expression</a> du langage de requête de liste de lecture intelligente.",
|
||||
"no-albums": "Aucun album trouvé",
|
||||
"no-artists": "Aucun artiste trouvé",
|
||||
"no-audiobooks": "Aucun livre audio trouvé",
|
||||
"no-composers": "Aucun compositeur trouvé",
|
||||
"no-playlists": "Aucune liste de lecture trouvée",
|
||||
"no-podcasts": "Aucune podcast trouvé",
|
||||
"no-tracks": "Aucune piste trouvée",
|
||||
"playlists": "Listes de lecture",
|
||||
"podcasts": "Podcasts",
|
||||
"show-albums": "Afficher les {count} albums",
|
||||
"show-artists": "Afficher les {count} artistes",
|
||||
"show-audiobooks": "Afficher les {count} livres audio",
|
||||
"show-composers": "Afficher les {count} compositeurs",
|
||||
"show-playlists": "Afficher les {count} listes de lecture",
|
||||
"show-podcasts": "Afficher les {count} podcasts",
|
||||
"show-tracks": "Afficher les {count} pistes",
|
||||
"pistes": "Pistes"
|
||||
},
|
||||
"settings": {
|
||||
"artwork": {
|
||||
"artwork": "Illustrations",
|
||||
"coverartarchive": "Cover Art Archive",
|
||||
"discogs": "Discogs",
|
||||
"explanation-1": "Prend en charge les illustrations au format PNG et JPEG qui sont soit placées dans la bibliothèque en tant que fichiers image séparés, soit intégrées dans les fichiers média, soit mises à disposition en ligne par les stations de radio.",
|
||||
"explanation-2": "En outre, vous pouvez activer la récupération des illustrations à partir des fournisseurs d’illustrations suivants :",
|
||||
"spotify": "Spotify"
|
||||
},
|
||||
"devices": {
|
||||
"no-active-pairing": "Aucune demande de jumelage active.",
|
||||
"pairing-request": "Demande de jumelage de télécommande ",
|
||||
"pairing": "Jumelage de télécommande",
|
||||
"send": "Envoyer",
|
||||
"speaker-pairing-info": "Si votre enceinte nécessite un jumelage, activez-la ci-dessous et entrez le code PIN qu’elle affiche.",
|
||||
"speaker-pairing": "Jumelage d’enceinte et vérification d’appareil",
|
||||
"verification-code": "Code de vérification",
|
||||
"verify": "Vérifier"
|
||||
},
|
||||
"general": {
|
||||
"album-lists": "Listes d’album",
|
||||
"audiobooks": "Livres audio",
|
||||
"files": "Fichiers audio",
|
||||
"language": "Langue",
|
||||
"music": "Musique",
|
||||
"navigation-item-selection-info": "Si vous sélectionnez plus d’éléments que ce qui peut être affiché sur votre écran, le menu disparaîtra.",
|
||||
"navigation-item-selection": "Sélectionnez les éléments de la barre de navigation supérieure",
|
||||
"navigation-items": "Barre de navigation",
|
||||
"now-playing-page": "Now playing page",
|
||||
"playlists": "Listes de lecture",
|
||||
"podcasts": "Podcasts",
|
||||
"radio": "Radio",
|
||||
"recently-added-page-info": "Limiter le nombre d’album affichés dans la section \"Ajouts récents\"",
|
||||
"recently-added-page": "Recently added page",
|
||||
"search": "Search",
|
||||
"show-composer-genres-info-1": "Liste des genres, séparés par des virgules, que le compositeur doit afficher sur la page \"Lecture en cours\".",
|
||||
"show-composer-genres-info-2": "Laissez vide pour toujours afficher le compositeur.",
|
||||
"show-composer-genres-info-3": "L’étiquette de genre de la piste actuelle est comparée en vérifiant si l’un des genres définis est inclus. Par exemple, en choisissant \"classique, bande sonore\", le compositeur pour les pistes dont l’étiquette de genre est \"classique contemporain\" sera affiché.",
|
||||
"show-composer-genres": "Afficher le compositeur uniquement pour les genres listés",
|
||||
"show-composer-info": "Si actif, le compositeur de la piste en cours de lecture est affiché sur la page \"lecture en cours\"",
|
||||
"show-composer": "Afficher le compositeur",
|
||||
"show-coverart": "Afficher les illustration dans la liste d’albums"
|
||||
},
|
||||
"services": {
|
||||
"lastfm": {
|
||||
"grant-access": "<b>Last.fm</b> - Connectez-vous avec votre nom d’utilisateur et votre mot de passe Last.fm pour activer le scrobbling.",
|
||||
"info": "Le nom d’utilisateur et le mot de passe Last.fm ne sont pas enregistrés, uniquement la clé de session. La clé de session n’expire pas.",
|
||||
"title": "Last.fm",
|
||||
"no-support": "L’option Last.fm n’est pas présente.",
|
||||
"stop-scrobbling": "Arrêter le scrobbling"
|
||||
},
|
||||
"spotify": {
|
||||
"no-support": "L’option Spotify n’est pas présente.",
|
||||
"help": "Si vous vous connectez habituellement à Spotify avec votre compte Facebook, vous devez d’abord vous rendre sur le site de Spotify pour obtenir le nom d’utilisateur et le mot de passe correspondant à votre compte.",
|
||||
"logged-as": "Connecté en tant que ",
|
||||
"requirements": "Vous devez posséder un compte Spotify Premium.",
|
||||
"scopes": "L’accès à l’API de Spotify permet l’analyse de votre bibliothèque Spotify. Les champs d’application requis sont les suivants :",
|
||||
"user": "Accès autorisé pour ",
|
||||
"authorize": "Autoriser l’accès à l’API",
|
||||
"credentials": " - Connectez-vous avec votre nom d’utilisateur et mot de passe Spotify",
|
||||
"grant-access": "<b>Spotify</b> - Accordez l’accès à l’API de Spotify",
|
||||
"help-1": "La bibliothèque libspotify permet de lire les pistes de Spotify.",
|
||||
"help-2": "Votre nom d’utilisateur et votre mot de passe Spotify ne sont pas enregistrés, uniquement le jeton de connexion.",
|
||||
"reauthorize": "Veuillez autoriser à nouveau l’accès à l’API pour accorder à OwnTone les droits d’accès supplémentaires suivants :",
|
||||
"title": "Spotify"
|
||||
},
|
||||
"login": "Se connecter",
|
||||
"logout": "Se déconnecter"
|
||||
},
|
||||
"tabs": {
|
||||
"music": {
|
||||
"albums": "Albums",
|
||||
"artists": "Artistes",
|
||||
"browse": "Parcourir",
|
||||
"composers": "Compositeurs",
|
||||
"genres": "Genres",
|
||||
"spotify": "Spotify"
|
||||
},
|
||||
"search": {
|
||||
"library": "Library",
|
||||
"spotify": "Spotify"
|
||||
},
|
||||
"settings": {
|
||||
"artwork": "Illustrations",
|
||||
"general": "Général",
|
||||
"online-services": "Services en ligne",
|
||||
"remotes-and-outputs": "Télécommandes et sorties"
|
||||
}
|
||||
}
|
||||
},
|
||||
"spotify": {
|
||||
"album": {
|
||||
"shuffle": "Lecture aléatoire",
|
||||
"track-count": "{count} pistes"
|
||||
},
|
||||
"artiste": {
|
||||
"album-count": "{count} albums",
|
||||
"shuffle": "Lecture aléatoire"
|
||||
},
|
||||
"browse": {
|
||||
"featured-playlists": "Listes de lecture en vedette",
|
||||
"new-releases": "Nouvelle sorties",
|
||||
"show-more": "Afficher plus"
|
||||
},
|
||||
"playlist": {
|
||||
"count": "{count} pistes",
|
||||
"shuffle": "Lecture aléatoire"
|
||||
},
|
||||
"search": {
|
||||
"albums": "Albums",
|
||||
"artists": "Artistes",
|
||||
"no-albums": "Aucun album trouvé",
|
||||
"no-artists": "Aucun artiste trouvé",
|
||||
"no-playlists": "Aucune liste de lecture trouvée",
|
||||
"no-tracks": "Aucune piste trouvée",
|
||||
"playlists": "Listes de lecture",
|
||||
"show-all-albums": "Afficher les {count} albums",
|
||||
"show-all-artists": "Afficher les {count} artistes",
|
||||
"show-all-playlists": "Afficher les {count} listes de lecture",
|
||||
"show-all-tracks": "Afficher les {count} pistes",
|
||||
"pistes": "Pistes"
|
||||
}
|
||||
}
|
||||
},
|
||||
"setting": {
|
||||
"not-saved": " (erreur à l’enregistrement du réglage)",
|
||||
"saved": " (réglage enregistré)"
|
||||
},
|
||||
"server": {
|
||||
"connection-failed": "Échec de connexion au serveur",
|
||||
"missing-port": "Port websocket manquant",
|
||||
"request-failed": "La requête a échoué (status: {status} {cause} {url})",
|
||||
"queue-saved": "La file d’attente enregistrée dans la liste de lecture {name}",
|
||||
"appended-tracks": "{count} pistes ajoutées à la file d’attente",
|
||||
"empty-queue": "La file d’attente est vide"
|
||||
},
|
||||
"group-by-list": {
|
||||
"today": "Aujourd’hui",
|
||||
"last-week": "La semaine dernière",
|
||||
"last-month": "Le mois dernier"
|
||||
}
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
import { createApp } from 'vue'
|
||||
import i18n from './i18n'
|
||||
import store from './store'
|
||||
import { router } from './router'
|
||||
import VueProgressBar from '@aacassandra/vue3-progressbar'
|
||||
@ -30,6 +31,7 @@ const app = createApp(App)
|
||||
.use(mdiVue, {
|
||||
icons: icons
|
||||
})
|
||||
.use(i18n)
|
||||
|
||||
app.config.globalProperties.$filters = filters
|
||||
app.mount('#app')
|
||||
|
@ -4,10 +4,7 @@
|
||||
<div class="container">
|
||||
<div class="columns is-centered">
|
||||
<div class="column is-four-fifths has-text-centered-mobile">
|
||||
<p class="heading"><b>OwnTone</b> - version {{ config.version }}</p>
|
||||
<h1 class="title is-4">
|
||||
{{ config.library_name }}
|
||||
</h1>
|
||||
<h1 class="title is-4" v-text="config.library_name" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -21,65 +18,84 @@
|
||||
<!-- Left side -->
|
||||
<div class="level-left">
|
||||
<div class="level-item">
|
||||
<h2 class="title is-5">Library</h2>
|
||||
<h2 class="title is-5" v-text="$t('page.about.library')" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Right side -->
|
||||
<div class="level-right">
|
||||
<div v-if="library.updating">
|
||||
<a class="button is-small is-loading">Update</a>
|
||||
<a
|
||||
class="button is-small is-loading"
|
||||
v-text="$t('page.about.update')"
|
||||
/>
|
||||
</div>
|
||||
<div v-else>
|
||||
<a class="button is-small" @click="showUpdateDialog()"
|
||||
>Update</a
|
||||
>
|
||||
<a
|
||||
class="button is-small"
|
||||
@click="showUpdateDialog()"
|
||||
v-text="$t('page.about.update')"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<table class="table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>Artists</th>
|
||||
<th class="has-text-left" v-text="$t('page.about.artists')" />
|
||||
<td
|
||||
class="has-text-right"
|
||||
v-text="$filters.number(library.artists)"
|
||||
/>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="has-text-left" v-text="$t('page.about.albums')" />
|
||||
<td
|
||||
class="has-text-right"
|
||||
v-text="$filters.number(library.albums)"
|
||||
/>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="has-text-left" v-text="$t('page.about.tracks')" />
|
||||
<td
|
||||
class="has-text-right"
|
||||
v-text="$filters.number(library.songs)"
|
||||
/>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="has-text-left" v-text="$t('page.about.total-playtime')" />
|
||||
<td
|
||||
class="has-text-right"
|
||||
v-text="
|
||||
$filters.durationInDays(library.db_playtime * 1000)
|
||||
"
|
||||
/>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="has-text-left" v-text="$t('page.about.updated')" />
|
||||
<td class="has-text-right">
|
||||
{{ $filters.number(library.artists) }}
|
||||
<span
|
||||
v-text="
|
||||
$t('page.about.updated-on', {
|
||||
time: $filters.timeFromNow(library.updated_at)
|
||||
})
|
||||
"
|
||||
/>
|
||||
(<span
|
||||
class="has-text-grey"
|
||||
v-text="$filters.datetime(library.updated_at)"
|
||||
/>)
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Albums</th>
|
||||
<th class="has-text-left" v-text="$t('page.about.uptime')" />
|
||||
<td class="has-text-right">
|
||||
{{ $filters.number(library.albums) }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Tracks</th>
|
||||
<td class="has-text-right">
|
||||
{{ $filters.number(library.songs) }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Total playtime</th>
|
||||
<td class="has-text-right">
|
||||
{{ $filters.durationInDays(library.db_playtime * 1000) }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Library updated</th>
|
||||
<td class="has-text-right">
|
||||
{{ $filters.timeFromNow(library.updated_at) }} ago
|
||||
<span class="has-text-grey"
|
||||
>({{ $filters.datetime(library.updated_at) }})</span
|
||||
>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Uptime</th>
|
||||
<td class="has-text-right">
|
||||
{{ $filters.timeFromNow(library.started_at, true) }}
|
||||
<span class="has-text-grey"
|
||||
>({{ $filters.datetime(library.started_at) }})</span
|
||||
>
|
||||
<span
|
||||
v-text="$filters.timeFromNow(library.started_at, true)"
|
||||
/>
|
||||
(<span
|
||||
class="has-text-grey"
|
||||
v-text="$filters.datetime(library.started_at)"
|
||||
/>)
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
@ -94,20 +110,16 @@
|
||||
<div class="columns is-centered">
|
||||
<div class="column is-four-fifths">
|
||||
<div class="content has-text-centered-mobile">
|
||||
<p class="is-size-7">
|
||||
Compiled with support for {{ config.buildoptions.join(', ') }}.
|
||||
</p>
|
||||
<p class="is-size-7">
|
||||
Web interface built with <a href="http://bulma.io">Bulma</a>,
|
||||
<a href="https://materialdesignicons.com/"
|
||||
>Material Design Icons</a
|
||||
>, <a href="https://vuejs.org/">Vue.js</a>,
|
||||
<a href="https://github.com/mzabriskie/axios">axios</a> and
|
||||
<a
|
||||
href="https://github.com/owntone/owntone-server/network/dependencies"
|
||||
>more</a
|
||||
>.
|
||||
</p>
|
||||
<p class="is-size-7" v-text="$t('page.about.version', { version: config.version })" />
|
||||
<p
|
||||
class="is-size-7"
|
||||
v-text="
|
||||
$t('page.about.compiled-with', {
|
||||
options: config.buildoptions.join(', ')
|
||||
})
|
||||
"
|
||||
/>
|
||||
<p class="is-size-7" v-html="$t('page.about.built-with')" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,23 +1,20 @@
|
||||
<template>
|
||||
<content-with-hero>
|
||||
<template #heading-left>
|
||||
<h1 class="title is-5">
|
||||
{{ album.name }}
|
||||
</h1>
|
||||
<h1 class="title is-5" v-text="album.name" />
|
||||
<h2 class="subtitle is-6 has-text-link has-text-weight-normal">
|
||||
<a class="has-text-link" @click="open_artist">{{ album.artist }}</a>
|
||||
<a class="has-text-link" @click="open_artist" v-text="album.artist" />
|
||||
</h2>
|
||||
|
||||
<div class="buttons fd-is-centered-mobile fd-has-margin-top">
|
||||
<a class="button is-small is-dark is-rounded" @click="play">
|
||||
<span class="icon"><mdicon name="shuffle" size="16" /></span>
|
||||
<span>Shuffle</span>
|
||||
<mdicon class="icon" name="shuffle" size="16" />
|
||||
<span v-text="$t('page.album.shuffle')" />
|
||||
</a>
|
||||
<a
|
||||
class="button is-small is-light is-rounded"
|
||||
@click="show_album_details_modal = true"
|
||||
>
|
||||
<span class="icon"><mdicon name="dots-horizontal" size="16" /></span>
|
||||
<mdicon class="icon" name="dots-horizontal" size="16" />
|
||||
</a>
|
||||
</div>
|
||||
</template>
|
||||
@ -32,9 +29,10 @@
|
||||
</p>
|
||||
</template>
|
||||
<template #content>
|
||||
<p class="heading is-7 has-text-centered-mobile fd-has-margin-top">
|
||||
{{ album.track_count }} tracks
|
||||
</p>
|
||||
<p
|
||||
class="heading is-7 has-text-centered-mobile fd-has-margin-top"
|
||||
v-text="$t('page.album.track-count', { count: album.track_count })"
|
||||
/>
|
||||
<list-tracks :tracks="tracks" :uris="album.uri" />
|
||||
<modal-dialog-album
|
||||
:show="show_album_details_modal"
|
||||
|
@ -1,14 +1,16 @@
|
||||
<template>
|
||||
<div class="fd-page-with-tabs">
|
||||
<tabs-music />
|
||||
|
||||
<content-with-heading>
|
||||
<template #options>
|
||||
<index-button-list :index="albums.indexList" />
|
||||
|
||||
<div class="columns">
|
||||
<div class="column">
|
||||
<p class="heading" style="margin-bottom: 24px">Filter</p>
|
||||
<p
|
||||
class="heading"
|
||||
style="margin-bottom: 24px"
|
||||
v-text="$t('page.albums.filter')"
|
||||
/>
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
<input
|
||||
@ -18,12 +20,12 @@
|
||||
name="switchHideSingles"
|
||||
class="switch"
|
||||
/>
|
||||
<label for="switchHideSingles">Hide singles</label>
|
||||
<label
|
||||
for="switchHideSingles"
|
||||
v-text="$t('page.albums.hide-singles')"
|
||||
/>
|
||||
</div>
|
||||
<p class="help">
|
||||
If active, hides singles and albums with tracks that only appear
|
||||
in playlists.
|
||||
</p>
|
||||
<p class="help" v-text="$t('page.albums.hide-singles-help')" />
|
||||
</div>
|
||||
<div v-if="spotify_enabled" class="field">
|
||||
<div class="control">
|
||||
@ -34,26 +36,33 @@
|
||||
name="switchHideSpotify"
|
||||
class="switch"
|
||||
/>
|
||||
<label for="switchHideSpotify">Hide albums from Spotify</label>
|
||||
<label
|
||||
for="switchHideSpotify"
|
||||
v-text="$t('page.albums.hide-spotify')"
|
||||
/>
|
||||
</div>
|
||||
<p class="help">
|
||||
If active, hides albums that only appear in your Spotify
|
||||
library.
|
||||
</p>
|
||||
<p class="help" v-text="$t('page.albums.hide-spotify-help')" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="column">
|
||||
<p class="heading" style="margin-bottom: 24px">Sort by</p>
|
||||
<p
|
||||
class="heading"
|
||||
style="margin-bottom: 24px"
|
||||
v-text="$t('page.albums.sort-by.title')"
|
||||
/>
|
||||
<dropdown-menu
|
||||
v-model="selected_groupby_option_name"
|
||||
:options="groupby_option_names"
|
||||
v-model="selected_groupby_option_id"
|
||||
:options="groupby_options"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #heading-left>
|
||||
<p class="title is-4">Albums</p>
|
||||
<p class="heading">{{ albums.count }} Albums</p>
|
||||
<p class="title is-4" v-text="$t('page.albums.title')" />
|
||||
<p
|
||||
class="heading"
|
||||
v-text="$t('page.albums.count', { count: albums.count })"
|
||||
/>
|
||||
</template>
|
||||
<template #heading-right />
|
||||
<template #content>
|
||||
@ -117,16 +126,22 @@ export default {
|
||||
|
||||
// List of group by/sort options for itemsGroupByList
|
||||
groupby_options: [
|
||||
{ name: 'Name', options: bySortName('name_sort') },
|
||||
{
|
||||
name: 'Recently added',
|
||||
id: 1,
|
||||
name: this.$t('page.albums.sort-by.name'),
|
||||
options: bySortName('name_sort')
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: this.$t('page.albums.sort-by.recently-added'),
|
||||
options: byYear('time_added', {
|
||||
direction: 'desc',
|
||||
defaultValue: '0000'
|
||||
})
|
||||
},
|
||||
{
|
||||
name: 'Recently released',
|
||||
id: 3,
|
||||
name: this.$t('page.albums.sort-by.recently-released'),
|
||||
options: byYear('date_released', {
|
||||
direction: 'desc',
|
||||
defaultValue: '0000'
|
||||
@ -139,7 +154,7 @@ export default {
|
||||
computed: {
|
||||
albums() {
|
||||
const groupBy = this.groupby_options.find(
|
||||
(o) => o.name === this.selected_groupby_option_name
|
||||
(o) => o.id === this.selected_groupby_option_id
|
||||
)
|
||||
this.albums_list.group(groupBy.options, [
|
||||
(album) => !this.hide_singles || album.track_count > 2,
|
||||
@ -149,11 +164,7 @@ export default {
|
||||
return this.albums_list
|
||||
},
|
||||
|
||||
groupby_option_names() {
|
||||
return [...this.groupby_options].map((o) => o.name)
|
||||
},
|
||||
|
||||
selected_groupby_option_name: {
|
||||
selected_groupby_option_id: {
|
||||
get() {
|
||||
return this.$store.state.albums_sort
|
||||
},
|
||||
|
@ -3,18 +3,20 @@
|
||||
<template #options>
|
||||
<div class="columns">
|
||||
<div class="column">
|
||||
<p class="heading" style="margin-bottom: 24px">Sort by</p>
|
||||
<p
|
||||
class="heading"
|
||||
style="margin-bottom: 24px"
|
||||
v-text="$t('page.artist.sort-by.title')"
|
||||
/>
|
||||
<dropdown-menu
|
||||
v-model="selected_groupby_option_name"
|
||||
:options="groupby_option_names"
|
||||
v-model="selected_groupby_option_id"
|
||||
:options="groupby_options"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #heading-left>
|
||||
<p class="title is-4">
|
||||
{{ artist.name }}
|
||||
</p>
|
||||
<p class="title is-4" v-text="artist.name" />
|
||||
</template>
|
||||
<template #heading-right>
|
||||
<div class="buttons is-centered">
|
||||
@ -22,20 +24,24 @@
|
||||
class="button is-small is-light is-rounded"
|
||||
@click="show_artist_details_modal = true"
|
||||
>
|
||||
<span class="icon"><mdicon name="dots-horizontal" size="16" /></span>
|
||||
<mdicon class="icon" name="dots-horizontal" size="16" />
|
||||
</a>
|
||||
<a class="button is-small is-dark is-rounded" @click="play">
|
||||
<span class="icon"><mdicon name="shuffle" size="16" /></span>
|
||||
<span>Shuffle</span>
|
||||
<mdicon class="icon" name="shuffle" size="16" />
|
||||
<span v-text="$t('page.artist.shuffle')" />
|
||||
</a>
|
||||
</div>
|
||||
</template>
|
||||
<template #content>
|
||||
<p class="heading has-text-centered-mobile">
|
||||
{{ artist.album_count }} albums |
|
||||
<a class="has-text-link" @click="open_tracks"
|
||||
>{{ artist.track_count }} tracks</a
|
||||
>
|
||||
<span
|
||||
v-text="$t('page.artist.album-count', { count: artist.album_count })"
|
||||
/>
|
||||
<a
|
||||
class="has-text-link"
|
||||
@click="open_tracks"
|
||||
v-text="$t('page.artist.track-count', { count: artist.track_count })"
|
||||
/>
|
||||
</p>
|
||||
<list-albums :albums="albums" :hide_group_title="true" />
|
||||
<modal-dialog-artist
|
||||
@ -99,9 +105,14 @@ export default {
|
||||
|
||||
// List of group by/sort options for itemsGroupByList
|
||||
groupby_options: [
|
||||
{ name: 'Name', options: bySortName('name_sort') },
|
||||
{
|
||||
name: 'Release date',
|
||||
id: 1,
|
||||
name: this.$t('page.artist.sort-by.name'),
|
||||
options: bySortName('name_sort')
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: this.$t('page.artist.sort-by.release-date'),
|
||||
options: byYear('date_released', {
|
||||
direction: 'asc',
|
||||
defaultValue: '0000'
|
||||
@ -116,18 +127,14 @@ export default {
|
||||
computed: {
|
||||
albums() {
|
||||
const groupBy = this.groupby_options.find(
|
||||
(o) => o.name === this.selected_groupby_option_name
|
||||
(o) => o.name === this.selected_groupby_option_id
|
||||
)
|
||||
this.albums_list.group(groupBy.options)
|
||||
|
||||
return this.albums_list
|
||||
},
|
||||
|
||||
groupby_option_names() {
|
||||
return [...this.groupby_options].map((o) => o.name)
|
||||
},
|
||||
|
||||
selected_groupby_option_name: {
|
||||
selected_groupby_option_id: {
|
||||
get() {
|
||||
return this.$store.state.artist_albums_sort
|
||||
},
|
||||
|
@ -5,9 +5,7 @@
|
||||
<index-button-list :index="index_list" />
|
||||
</template>
|
||||
<template #heading-left>
|
||||
<p class="title is-4">
|
||||
{{ artist.name }}
|
||||
</p>
|
||||
<p class="title is-4" v-text="artist.name" />
|
||||
</template>
|
||||
<template #heading-right>
|
||||
<div class="buttons is-centered">
|
||||
@ -15,22 +13,26 @@
|
||||
class="button is-small is-light is-rounded"
|
||||
@click="show_artist_details_modal = true"
|
||||
>
|
||||
<span class="icon"
|
||||
><mdicon name="dots-horizontal" size="16"
|
||||
/></span>
|
||||
<mdicon class="icon" name="dots-horizontal" size="16" />
|
||||
</a>
|
||||
<a class="button is-small is-dark is-rounded" @click="play">
|
||||
<span class="icon"><mdicon name="shuffle" size="16" /></span>
|
||||
<span>Shuffle</span>
|
||||
<mdicon class="icon" name="shuffle" size="16" />
|
||||
<span v-text="$t('page.artist.shuffle')" />
|
||||
</a>
|
||||
</div>
|
||||
</template>
|
||||
<template #content>
|
||||
<p class="heading has-text-centered-mobile">
|
||||
<a class="has-text-link" @click="open_artist"
|
||||
>{{ artist.album_count }} albums</a
|
||||
>
|
||||
| {{ artist.track_count }} tracks
|
||||
<a
|
||||
class="has-text-link"
|
||||
@click="open_artist"
|
||||
v-text="
|
||||
$t('page.artist.track-count', {
|
||||
albums: artist.album_count,
|
||||
tracks: artist.track_count
|
||||
})
|
||||
"
|
||||
/>
|
||||
</p>
|
||||
<list-tracks :tracks="tracks.items" :uris="track_uris" />
|
||||
<modal-dialog-artist
|
||||
|
@ -1,14 +1,16 @@
|
||||
<template>
|
||||
<div class="fd-page-with-tabs">
|
||||
<tabs-music />
|
||||
|
||||
<content-with-heading>
|
||||
<template #options>
|
||||
<index-button-list :index="artists.indexList" />
|
||||
|
||||
<div class="columns">
|
||||
<div class="column">
|
||||
<p class="heading" style="margin-bottom: 24px">Filter</p>
|
||||
<p
|
||||
class="heading"
|
||||
style="margin-bottom: 24px"
|
||||
v-text="$t('page.artists.filter')"
|
||||
/>
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
<input
|
||||
@ -18,12 +20,12 @@
|
||||
name="switchHideSingles"
|
||||
class="switch"
|
||||
/>
|
||||
<label for="switchHideSingles">Hide singles</label>
|
||||
<label
|
||||
for="switchHideSingles"
|
||||
v-text="$t('page.artists.hide-singles')"
|
||||
/>
|
||||
</div>
|
||||
<p class="help">
|
||||
If active, hides artists that only appear on singles or
|
||||
playlists.
|
||||
</p>
|
||||
<p class="help" v-text="$t('page.artists.hide-singles-help')" />
|
||||
</div>
|
||||
<div v-if="spotify_enabled" class="field">
|
||||
<div class="control">
|
||||
@ -34,26 +36,33 @@
|
||||
name="switchHideSpotify"
|
||||
class="switch"
|
||||
/>
|
||||
<label for="switchHideSpotify">Hide artists from Spotify</label>
|
||||
<label
|
||||
for="switchHideSpotify"
|
||||
v-text="$t('page.artists.hide-spotify')"
|
||||
/>
|
||||
</div>
|
||||
<p class="help">
|
||||
If active, hides artists that only appear in your Spotify
|
||||
library.
|
||||
</p>
|
||||
<p class="help" v-text="$t('page.artists.hide-spotify-help')" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="column">
|
||||
<p class="heading" style="margin-bottom: 24px">Sort by</p>
|
||||
<p
|
||||
class="heading"
|
||||
style="margin-bottom: 24px"
|
||||
v-text="$t('page.artists.sort-by.title')"
|
||||
/>
|
||||
<dropdown-menu
|
||||
v-model="selected_groupby_option_name"
|
||||
:options="groupby_option_names"
|
||||
v-model="selected_groupby_option_id"
|
||||
:options="groupby_options"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #heading-left>
|
||||
<p class="title is-4">Artists</p>
|
||||
<p class="heading">{{ artists.count }} Artists</p>
|
||||
<p class="title is-4" v-text="$t('page.artists.title')" />
|
||||
<p
|
||||
class="heading"
|
||||
v-text="$t('page.artists.count', { count: artists.count })"
|
||||
/>
|
||||
</template>
|
||||
<template #heading-right />
|
||||
<template #content>
|
||||
@ -118,9 +127,14 @@ export default {
|
||||
|
||||
// List of group by/sort options for itemsGroupByList
|
||||
groupby_options: [
|
||||
{ name: 'Name', options: bySortName('name_sort') },
|
||||
{
|
||||
name: 'Recently added',
|
||||
id: 1,
|
||||
name: this.$t('page.artists.sort-by.name'),
|
||||
options: bySortName('name_sort')
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: this.$t('page.artists.sort-by.recently-added'),
|
||||
options: byYear('time_added', {
|
||||
direction: 'desc',
|
||||
defaultValue: '0000'
|
||||
@ -138,7 +152,7 @@ export default {
|
||||
}
|
||||
|
||||
const groupBy = this.groupby_options.find(
|
||||
(o) => o.name === this.selected_groupby_option_name
|
||||
(o) => o.id === this.selected_groupby_option_id
|
||||
)
|
||||
this.artists_list.group(groupBy.options, [
|
||||
(artist) =>
|
||||
@ -149,12 +163,7 @@ export default {
|
||||
return this.artists_list
|
||||
},
|
||||
|
||||
// List for the drop down menu
|
||||
groupby_option_names() {
|
||||
return [...this.groupby_options].map((o) => o.name)
|
||||
},
|
||||
|
||||
selected_groupby_option_name: {
|
||||
selected_groupby_option_id: {
|
||||
get() {
|
||||
return this.$store.state.artists_sort
|
||||
},
|
||||
|
@ -1,23 +1,20 @@
|
||||
<template>
|
||||
<content-with-hero>
|
||||
<template #heading-left>
|
||||
<h1 class="title is-5">
|
||||
{{ album.name }}
|
||||
</h1>
|
||||
<h1 class="title is-5" v-text="album.name" />
|
||||
<h2 class="subtitle is-6 has-text-link has-text-weight-normal">
|
||||
<a class="has-text-link" @click="open_artist">{{ album.artist }}</a>
|
||||
<a class="has-text-link" @click="open_artist" v-text="album.artist" />
|
||||
</h2>
|
||||
|
||||
<div class="buttons fd-is-centered-mobile fd-has-margin-top">
|
||||
<a class="button is-small is-dark is-rounded" @click="play">
|
||||
<span class="icon"><mdicon name="play" size="16" /></span>
|
||||
<span>Play</span>
|
||||
<mdicon class="icon" name="play" size="16" />
|
||||
<span v-text="$t('page.audiobooks.album.play')" />
|
||||
</a>
|
||||
<a
|
||||
class="button is-small is-light is-rounded"
|
||||
@click="show_album_details_modal = true"
|
||||
>
|
||||
<span class="icon"><mdicon name="dots-horizontal" size="16" /></span>
|
||||
<mdicon class="icon" name="dots-horizontal" size="16" />
|
||||
</a>
|
||||
</div>
|
||||
</template>
|
||||
@ -32,9 +29,12 @@
|
||||
</p>
|
||||
</template>
|
||||
<template #content>
|
||||
<p class="heading is-7 has-text-centered-mobile fd-has-margin-top">
|
||||
{{ album.track_count }} tracks
|
||||
</p>
|
||||
<p
|
||||
class="heading is-7 has-text-centered-mobile fd-has-margin-top"
|
||||
v-text="
|
||||
$t('page.audiobooks.album.track-count', { count: album.track_count })
|
||||
"
|
||||
/>
|
||||
<list-tracks :tracks="tracks" :uris="album.uri" />
|
||||
<modal-dialog-album
|
||||
:show="show_album_details_modal"
|
||||
|
@ -1,14 +1,16 @@
|
||||
<template>
|
||||
<div class="fd-page-with-tabs">
|
||||
<tabs-audiobooks />
|
||||
|
||||
<content-with-heading>
|
||||
<template #options>
|
||||
<index-button-list :index="albums.indexList" />
|
||||
</template>
|
||||
<template #heading-left>
|
||||
<p class="title is-4">Audiobooks</p>
|
||||
<p class="heading">{{ albums.count }} Audiobooks</p>
|
||||
<p class="title is-4" v-text="$t('page.audiobooks.albums.title')" />
|
||||
<p
|
||||
class="heading"
|
||||
v-text="$t('page.audiobooks.albums.count', { count: albums.count })"
|
||||
/>
|
||||
</template>
|
||||
<template #content>
|
||||
<list-albums :albums="albums" />
|
||||
|
@ -1,9 +1,7 @@
|
||||
<template>
|
||||
<content-with-heading>
|
||||
<template #heading-left>
|
||||
<p class="title is-4">
|
||||
{{ artist.name }}
|
||||
</p>
|
||||
<p class="title is-4" v-text="artist.name" />
|
||||
</template>
|
||||
<template #heading-right>
|
||||
<div class="buttons is-centered">
|
||||
@ -11,18 +9,23 @@
|
||||
class="button is-small is-light is-rounded"
|
||||
@click="show_artist_details_modal = true"
|
||||
>
|
||||
<span class="icon"><mdicon name="dots-horizontal" size="16" /></span>
|
||||
<mdicon class="icon" name="dots-horizontal" size="16" />
|
||||
</a>
|
||||
<a class="button is-small is-dark is-rounded" @click="play">
|
||||
<span class="icon"><mdicon name="play" size="16" /></span>
|
||||
<span>Shuffle</span>
|
||||
<mdicon class="icon" name="play" size="16" />
|
||||
<span v-text="$t('page.audiobooks.artist.shuffle')" />
|
||||
</a>
|
||||
</div>
|
||||
</template>
|
||||
<template #content>
|
||||
<p class="heading has-text-centered-mobile">
|
||||
{{ artist.album_count }} albums
|
||||
</p>
|
||||
<p
|
||||
class="heading has-text-centered-mobile"
|
||||
v-text="
|
||||
$t('page.audiobooks.artist.album-count', {
|
||||
count: artist.album_count
|
||||
})
|
||||
"
|
||||
/>
|
||||
<list-albums :albums="albums" />
|
||||
<modal-dialog-artist
|
||||
:show="show_artist_details_modal"
|
||||
|
@ -1,14 +1,16 @@
|
||||
<template>
|
||||
<div class="fd-page-with-tabs">
|
||||
<tabs-audiobooks />
|
||||
|
||||
<content-with-heading>
|
||||
<template #options>
|
||||
<index-button-list :index="artists.indexList" />
|
||||
</template>
|
||||
<template #heading-left>
|
||||
<p class="title is-4">Authors</p>
|
||||
<p class="heading">{{ artists.count }} Authors</p>
|
||||
<p class="title is-4" v-text="$t('page.audiobooks.artists.title')" />
|
||||
<p
|
||||
class="heading"
|
||||
v-text="$t('page.audiobooks.artists.count', { count: tists.count })"
|
||||
/>
|
||||
</template>
|
||||
<template #heading-right />
|
||||
<template #content>
|
||||
|
@ -1,12 +1,11 @@
|
||||
<template>
|
||||
<div class="fd-page-with-tabs">
|
||||
<tabs-music />
|
||||
|
||||
<!-- Recently added -->
|
||||
<content-with-heading>
|
||||
<template #heading-left>
|
||||
<p class="title is-4">Recently added</p>
|
||||
<p class="heading">albums</p>
|
||||
<p class="title is-4" v-text="$t('page.browse.recently-added.title')" />
|
||||
<p class="heading" v-text="$t('page.browse.albums')" />
|
||||
</template>
|
||||
<template #content>
|
||||
<list-albums :albums="recently_added" />
|
||||
@ -17,18 +16,20 @@
|
||||
<a
|
||||
class="button is-light is-small is-rounded"
|
||||
@click="open_browse('recently_added')"
|
||||
>Show more</a
|
||||
>
|
||||
v-text="$t('page.browse.show-more')"
|
||||
/>
|
||||
</p>
|
||||
</nav>
|
||||
</template>
|
||||
</content-with-heading>
|
||||
|
||||
<!-- Recently played -->
|
||||
<content-with-heading>
|
||||
<template #heading-left>
|
||||
<p class="title is-4">Recently played</p>
|
||||
<p class="heading">tracks</p>
|
||||
<p
|
||||
class="title is-4"
|
||||
v-text="$t('page.browse.recently-played.title')"
|
||||
/>
|
||||
<p class="heading" v-text="$t('page.browse.tracks')" />
|
||||
</template>
|
||||
<template #content>
|
||||
<list-tracks :tracks="recently_played.items" />
|
||||
@ -39,8 +40,8 @@
|
||||
<a
|
||||
class="button is-light is-small is-rounded"
|
||||
@click="open_browse('recently_played')"
|
||||
>Show more</a
|
||||
>
|
||||
v-text="$t('page.browse.show-more')"
|
||||
/>
|
||||
</p>
|
||||
</nav>
|
||||
</template>
|
||||
|
@ -1,11 +1,10 @@
|
||||
<template>
|
||||
<div class="fd-page-with-tabs">
|
||||
<tabs-music />
|
||||
|
||||
<content-with-heading>
|
||||
<template #heading-left>
|
||||
<p class="title is-4">Recently added</p>
|
||||
<p class="heading">albums</p>
|
||||
<p class="title is-4" v-text="$t('page.browse.recently-added.title')" />
|
||||
<p class="heading" v-text="$t('page.browse.recently-added.albums')" />
|
||||
</template>
|
||||
<template #content>
|
||||
<list-albums :albums="recently_added" />
|
||||
|
@ -1,11 +1,13 @@
|
||||
<template>
|
||||
<div class="fd-page-with-tabs">
|
||||
<tabs-music />
|
||||
|
||||
<content-with-heading>
|
||||
<template #heading-left>
|
||||
<p class="title is-4">Recently played</p>
|
||||
<p class="heading">tracks</p>
|
||||
<p
|
||||
class="title is-4"
|
||||
v-text="$t('page.browse.recently.played.title')"
|
||||
/>
|
||||
<p class="heading" v-text="$t('page.browse.recently.played.tracks')" />
|
||||
</template>
|
||||
<template #content>
|
||||
<list-tracks :tracks="recently_played.items" />
|
||||
|
@ -2,9 +2,7 @@
|
||||
<div>
|
||||
<content-with-heading>
|
||||
<template #heading-left>
|
||||
<p class="title is-4">
|
||||
{{ composer.name }}
|
||||
</p>
|
||||
<p class="title is-4" v-text="composer.name" />
|
||||
</template>
|
||||
<template #heading-right>
|
||||
<div class="buttons is-centered">
|
||||
@ -12,25 +10,30 @@
|
||||
class="button is-small is-light is-rounded"
|
||||
@click="show_composer_details_modal = true"
|
||||
>
|
||||
<span class="icon"
|
||||
><mdicon name="dots-horizontal" size="16"
|
||||
/></span>
|
||||
<mdicon class="icon" name="dots-horizontal" size="16" />
|
||||
</a>
|
||||
<a class="button is-small is-dark is-rounded" @click="play">
|
||||
<span class="icon"><mdicon name="shuffle" size="16" /></span>
|
||||
<span>Shuffle</span>
|
||||
<mdicon class="icon" name="shuffle" size="16" />
|
||||
<span v-text="$t('page.composer.shuffle')" />
|
||||
</a>
|
||||
</div>
|
||||
</template>
|
||||
<template #content>
|
||||
<p class="heading has-text-centered-mobile">
|
||||
{{ composer.album_count }} albums |
|
||||
<a class="has-text-link" @click="open_tracks"
|
||||
>{{ composer.track_count }} tracks</a
|
||||
>
|
||||
<span
|
||||
v-text="
|
||||
$t('page.composer.album-count', { count: composer.album_count })
|
||||
"
|
||||
/>
|
||||
<a
|
||||
class="has-text-link"
|
||||
@click="open_tracks"
|
||||
v-text="
|
||||
$t('page.composer.track-count', { count: composer.track_count })
|
||||
"
|
||||
/>
|
||||
</p>
|
||||
<list-albums :albums="albums_list" :hide_group_title="true" />
|
||||
|
||||
<modal-dialog-composer
|
||||
:show="show_composer_details_modal"
|
||||
:composer="composer"
|
||||
|
@ -2,9 +2,7 @@
|
||||
<div>
|
||||
<content-with-heading>
|
||||
<template #heading-left>
|
||||
<p class="title is-4">
|
||||
{{ composer.name }}
|
||||
</p>
|
||||
<p class="title is-4" v-text="composer.name" />
|
||||
</template>
|
||||
<template #heading-right>
|
||||
<div class="buttons is-centered">
|
||||
@ -12,22 +10,30 @@
|
||||
class="button is-small is-light is-rounded"
|
||||
@click="show_composer_details_modal = true"
|
||||
>
|
||||
<span class="icon"
|
||||
><mdicon name="dots-horizontal" size="16"
|
||||
/></span>
|
||||
<mdicon class="icon" name="dots-horizontal" size="16" />
|
||||
</a>
|
||||
<a class="button is-small is-dark is-rounded" @click="play">
|
||||
<span class="icon"><mdicon name="shuffle" size="16" /></span>
|
||||
<span>Shuffle</span>
|
||||
<mdicon class="icon" name="shuffle" size="16" />
|
||||
<span v-text="$t('page.composer.tracks.shuffle')" />
|
||||
</a>
|
||||
</div>
|
||||
</template>
|
||||
<template #content>
|
||||
<p class="heading has-text-centered-mobile">
|
||||
<a class="has-text-link" @click="open_albums"
|
||||
>{{ composer.album_count }} albums</a
|
||||
>
|
||||
| {{ composer.track_count }} tracks
|
||||
<a
|
||||
class="has-text-link"
|
||||
@click="open_albums"
|
||||
v-text="
|
||||
$t('page.composer.tracks.album-count', {
|
||||
count: composer.album_count
|
||||
})
|
||||
"
|
||||
/>
|
||||
<span
|
||||
v-text="
|
||||
$t('page.composer.track-count', { count: composer.track_count })
|
||||
"
|
||||
/>
|
||||
</p>
|
||||
<list-tracks :tracks="tracks.items" :expression="play_expression" />
|
||||
<modal-dialog-composer
|
||||
|
@ -1,14 +1,16 @@
|
||||
<template>
|
||||
<div>
|
||||
<tabs-music />
|
||||
|
||||
<content-with-heading>
|
||||
<template #options>
|
||||
<index-button-list :index="composers.indexList" />
|
||||
</template>
|
||||
<template #heading-left>
|
||||
<p class="title is-4">Composers</p>
|
||||
<p class="heading">{{ composers.total }} composers</p>
|
||||
<p class="title is-4" v-text="$t('page.composers.title')" />
|
||||
<p
|
||||
class="heading"
|
||||
v-text="$t('page.composers.count', { count: composers.total })"
|
||||
/>
|
||||
</template>
|
||||
<template #content>
|
||||
<list-composers :composers="composers" />
|
||||
|
@ -2,10 +2,8 @@
|
||||
<div>
|
||||
<content-with-heading>
|
||||
<template #heading-left>
|
||||
<p class="title is-4">Files</p>
|
||||
<p class="title is-7 has-text-grey">
|
||||
{{ current_directory }}
|
||||
</p>
|
||||
<p class="title is-4" v-text="$t('page.files.title')" />
|
||||
<p class="title is-7 has-text-grey" v-text="current_directory" />
|
||||
</template>
|
||||
<template #heading-right>
|
||||
<div class="buttons is-centered">
|
||||
@ -13,27 +11,22 @@
|
||||
class="button is-small is-light is-rounded"
|
||||
@click="open_directory_dialog({ path: current_directory })"
|
||||
>
|
||||
<span class="icon"
|
||||
><mdicon name="dots-horizontal" size="16"
|
||||
/></span>
|
||||
<mdicon class="icon" name="dots-horizontal" size="16" />
|
||||
</a>
|
||||
<a class="button is-small is-dark is-rounded" @click="play">
|
||||
<span class="icon"><mdicon name="play" size="16" /></span>
|
||||
<span>Play</span>
|
||||
<mdicon class="icon" name="play" size="16" />
|
||||
<span v-text="$t('page.files.play')" />
|
||||
</a>
|
||||
</div>
|
||||
</template>
|
||||
<template #content>
|
||||
<list-directories :directories="files.directories" />
|
||||
|
||||
<list-playlists :playlists="files.playlists.items" />
|
||||
|
||||
<list-tracks
|
||||
:tracks="files.tracks.items"
|
||||
:expression="play_expression"
|
||||
:show_icon="true"
|
||||
/>
|
||||
|
||||
<modal-dialog-directory
|
||||
:show="show_directory_details_modal"
|
||||
:directory="selected_directory"
|
||||
|
@ -5,9 +5,7 @@
|
||||
<index-button-list :index="albums_list.indexList" />
|
||||
</template>
|
||||
<template #heading-left>
|
||||
<p class="title is-4">
|
||||
{{ genre.name }}
|
||||
</p>
|
||||
<p class="title is-4" v-text="genre.name" />
|
||||
</template>
|
||||
<template #heading-right>
|
||||
<div class="buttons is-centered">
|
||||
@ -15,22 +13,24 @@
|
||||
class="button is-small is-light is-rounded"
|
||||
@click="show_genre_details_modal = true"
|
||||
>
|
||||
<span class="icon"
|
||||
><mdicon name="dots-horizontal" size="16"
|
||||
/></span>
|
||||
<mdicon class="icon" name="dots-horizontal" size="16" />
|
||||
</a>
|
||||
<a class="button is-small is-dark is-rounded" @click="play">
|
||||
<span class="icon"><mdicon name="shuffle" size="16" /></span>
|
||||
<span>Shuffle</span>
|
||||
<mdicon class="icon" name="shuffle" size="16" />
|
||||
<span v-text="$t('page.genre.shuffle')" />
|
||||
</a>
|
||||
</div>
|
||||
</template>
|
||||
<template #content>
|
||||
<p class="heading has-text-centered-mobile">
|
||||
{{ genre.album_count }} albums |
|
||||
<a class="has-text-link" @click="open_tracks"
|
||||
>{{ genre.track_count }} tracks</a
|
||||
>
|
||||
<span
|
||||
v-text="$t('page.genre.album-count', { count: genre.album_count })"
|
||||
/>
|
||||
<a
|
||||
class="has-text-link"
|
||||
@click="open_tracks"
|
||||
v-text="$t('page.genre.track-count', { count: genre.track_count })"
|
||||
/>
|
||||
</p>
|
||||
<list-albums :albums="albums_list" />
|
||||
<modal-dialog-genre
|
||||
|
@ -5,9 +5,7 @@
|
||||
<index-button-list :index="index_list" />
|
||||
</template>
|
||||
<template #heading-left>
|
||||
<p class="title is-4">
|
||||
{{ genre.name }}
|
||||
</p>
|
||||
<p class="title is-4" v-text="genre.name" />
|
||||
</template>
|
||||
<template #heading-right>
|
||||
<div class="buttons is-centered">
|
||||
@ -15,22 +13,26 @@
|
||||
class="button is-small is-light is-rounded"
|
||||
@click="show_genre_details_modal = true"
|
||||
>
|
||||
<span class="icon"
|
||||
><mdicon name="dots-horizontal" size="16"
|
||||
/></span>
|
||||
<mdicon class="icon" name="dots-horizontal" size="16" />
|
||||
</a>
|
||||
<a class="button is-small is-dark is-rounded" @click="play">
|
||||
<span class="icon"><mdicon name="shuffle" size="16" /></span>
|
||||
<span>Shuffle</span>
|
||||
<mdicon class="icon" name="shuffle" size="16" />
|
||||
<span v-text="$t('page.genre.tracks.shuffle')" />
|
||||
</a>
|
||||
</div>
|
||||
</template>
|
||||
<template #content>
|
||||
<p class="heading has-text-centered-mobile">
|
||||
<a class="has-text-link" @click="open_genre"
|
||||
>{{ genre.album_count }} albums</a
|
||||
>
|
||||
| {{ genre.track_count }} tracks
|
||||
<a
|
||||
class="has-text-link"
|
||||
@click="open_genre"
|
||||
v-text="
|
||||
$t('page.genre.tracks.album-count', { count: genre.album_count })
|
||||
"
|
||||
/>
|
||||
<span
|
||||
v-text="$t('page.genre.tracks.count', { count: genre.track_count })"
|
||||
/>
|
||||
</p>
|
||||
<list-tracks :tracks="tracks.items" :expression="expression" />
|
||||
<modal-dialog-genre
|
||||
|
@ -1,14 +1,16 @@
|
||||
<template>
|
||||
<div class="fd-page-with-tabs">
|
||||
<tabs-music />
|
||||
|
||||
<content-with-heading>
|
||||
<template #options>
|
||||
<index-button-list :index="genres.indexList" />
|
||||
</template>
|
||||
<template #heading-left>
|
||||
<p class="title is-4">Genres</p>
|
||||
<p class="heading">{{ genres.total }} genres</p>
|
||||
<p class="title is-4" v-text="$t('page.genres.title')" />
|
||||
<p
|
||||
class="heading"
|
||||
v-text="$t('page.genres.count', { count: genres.total })"
|
||||
/>
|
||||
</template>
|
||||
<template #content>
|
||||
<list-genres :genres="genres" />
|
||||
|
@ -26,41 +26,29 @@
|
||||
@start="start_dragging"
|
||||
@end="end_dragging"
|
||||
/>
|
||||
<!--range-slider
|
||||
class="seek-slider fd-has-action"
|
||||
min="0"
|
||||
:max="state.item_length_ms"
|
||||
:value="item_progress_ms"
|
||||
:disabled="state.state === 'stop'"
|
||||
step="1000"
|
||||
@change="seek" >
|
||||
</range-slider-->
|
||||
</p>
|
||||
<p class="content">
|
||||
<span
|
||||
>{{ $filters.durationInHours(item_progress_ms) }} /
|
||||
{{ $filters.durationInHours(now_playing.length_ms) }}</span
|
||||
>
|
||||
v-text="
|
||||
[
|
||||
$filters.durationInHours(item_progress_ms),
|
||||
$filters.durationInHours(now_playing.length_ms)
|
||||
].join(' / ')
|
||||
"
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fd-has-padding-left-right">
|
||||
<div class="container has-text-centered fd-has-margin-top">
|
||||
<h1 class="title is-5">
|
||||
{{ now_playing.title }}
|
||||
</h1>
|
||||
<h2 class="title is-6">
|
||||
{{ now_playing.artist }}
|
||||
</h2>
|
||||
<h1 class="title is-5" v-text="now_playing.title" />
|
||||
<h2 class="title is-6" v-text="now_playing.artist" />
|
||||
<h2
|
||||
v-if="composer"
|
||||
class="subtitle is-6 has-text-grey has-text-weight-bold"
|
||||
>
|
||||
{{ composer }}
|
||||
</h2>
|
||||
<h3 class="subtitle is-6">
|
||||
{{ now_playing.album }}
|
||||
</h3>
|
||||
v-text="composer"
|
||||
/>
|
||||
<h3 class="subtitle is-6" v-text="now_playing.album" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -70,8 +58,8 @@
|
||||
style="flex-direction: column"
|
||||
>
|
||||
<div class="content has-text-centered">
|
||||
<h1 class="title is-5">Your play queue is empty</h1>
|
||||
<p>Add some tracks by browsing your library</p>
|
||||
<h1 class="title is-5" v-text="$('page.now-playing.title')" />
|
||||
<p v-text="$('page.now-playing.info')" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -85,7 +73,6 @@
|
||||
|
||||
<script>
|
||||
import ModalDialogQueueItem from '@/components/ModalDialogQueueItem.vue'
|
||||
//import RangeSlider from 'vue-range-slider'
|
||||
import Slider from '@vueform/slider'
|
||||
import CoverArtwork from '@/components/CoverArtwork.vue'
|
||||
import webapi from '@/webapi'
|
||||
@ -95,7 +82,6 @@ export default {
|
||||
name: 'PageNowPlaying',
|
||||
components: {
|
||||
ModalDialogQueueItem,
|
||||
// RangeSlider,
|
||||
Slider,
|
||||
CoverArtwork
|
||||
},
|
||||
|
@ -1,9 +1,7 @@
|
||||
<template>
|
||||
<content-with-heading>
|
||||
<template #heading-left>
|
||||
<div class="title is-4">
|
||||
{{ playlist.name }}
|
||||
</div>
|
||||
<div class="title is-4" v-text="playlist.name" />
|
||||
</template>
|
||||
<template #heading-right>
|
||||
<div class="buttons is-centered">
|
||||
@ -11,16 +9,19 @@
|
||||
class="button is-small is-light is-rounded"
|
||||
@click="show_playlist_details_modal = true"
|
||||
>
|
||||
<span class="icon"><mdicon name="dots-horizontal" size="16" /></span>
|
||||
<mdicon class="icon" name="dots-horizontal" size="16" />
|
||||
</a>
|
||||
<a class="button is-small is-dark is-rounded" @click="play">
|
||||
<span class="icon"><mdicon name="shuffle" size="16" /></span>
|
||||
<span>Shuffle</span>
|
||||
<mdicon class="icon" name="shuffle" size="16" />
|
||||
<span v-text="$t('page.playlist.shuffle')" />
|
||||
</a>
|
||||
</div>
|
||||
</template>
|
||||
<template #content>
|
||||
<p class="heading has-text-centered-mobile">{{ tracks.length }} tracks</p>
|
||||
<p
|
||||
class="heading has-text-centered-mobile"
|
||||
v-text="$t('page.playlist.length', { length: tracks.length })"
|
||||
/>
|
||||
<list-tracks :tracks="tracks" :uris="uris" />
|
||||
<modal-dialog-playlist
|
||||
:show="show_playlist_details_modal"
|
||||
|
@ -1,10 +1,11 @@
|
||||
<template>
|
||||
<content-with-heading>
|
||||
<template #heading-left>
|
||||
<p class="title is-4">
|
||||
{{ playlist.name }}
|
||||
</p>
|
||||
<p class="heading">{{ playlists.count }} playlists</p>
|
||||
<p class="title is-4" v-text="playlist.name" />
|
||||
<p
|
||||
class="heading"
|
||||
v-text="$t('page.playlists.count', { count: playlists.count })"
|
||||
/>
|
||||
</template>
|
||||
<template #content>
|
||||
<list-playlists :playlists="playlists" />
|
||||
|
@ -1,9 +1,7 @@
|
||||
<template>
|
||||
<content-with-heading>
|
||||
<template #heading-left>
|
||||
<div class="title is-4">
|
||||
{{ album.name }}
|
||||
</div>
|
||||
<div class="title is-4" v-text="album.name" />
|
||||
</template>
|
||||
<template #heading-right>
|
||||
<div class="buttons is-centered">
|
||||
@ -11,20 +9,19 @@
|
||||
class="button is-small is-light is-rounded"
|
||||
@click="show_album_details_modal = true"
|
||||
>
|
||||
<span class="icon"><mdicon name="dots-horizontal" size="16" /></span>
|
||||
<mdicon class="icon" name="dots-horizontal" size="16" />
|
||||
</a>
|
||||
<a class="button is-small is-dark is-rounded" @click="play">
|
||||
<span class="icon">
|
||||
<mdicon name="play" size="16" />
|
||||
</span>
|
||||
<span>Play</span>
|
||||
<mdicon class="icon" name="play" size="16" />
|
||||
<span v-text="$t('page.podcast.play')" />
|
||||
</a>
|
||||
</div>
|
||||
</template>
|
||||
<template #content>
|
||||
<p class="heading has-text-centered-mobile">
|
||||
{{ album.track_count }} tracks
|
||||
</p>
|
||||
<p
|
||||
class="heading has-text-centered-mobile"
|
||||
v-text="$t('page.podcast.track-count', { count: album.track_count })"
|
||||
/>
|
||||
<list-tracks
|
||||
:tracks="tracks"
|
||||
:show_progress="true"
|
||||
@ -47,11 +44,10 @@
|
||||
@delete="remove_podcast"
|
||||
>
|
||||
<template #modal-content>
|
||||
<p>Permanently remove this podcast from your library?</p>
|
||||
<p v-text="$t('page.podcast.remove-info-1')" />
|
||||
<p class="is-size-7">
|
||||
(This will also remove the RSS playlist
|
||||
<b>{{ rss_playlist_to_remove.name }}</b
|
||||
>.)
|
||||
(<span v-text="$t('page.podcast.remove-info-2')" />
|
||||
<b v-text="rss_playlist_to_remove.name" />)
|
||||
</p>
|
||||
</template>
|
||||
</modal-dialog>
|
||||
@ -131,7 +127,7 @@ export default {
|
||||
const rssPlaylists = data.items.filter((pl) => pl.type === 'rss')
|
||||
if (rssPlaylists.length !== 1) {
|
||||
this.$store.dispatch('add_notification', {
|
||||
text: 'Podcast cannot be removed. Probably it was not added as an RSS playlist.',
|
||||
text: this.$t('page.podcast.remove-error'),
|
||||
type: 'danger'
|
||||
})
|
||||
return
|
||||
|
@ -2,15 +2,13 @@
|
||||
<div>
|
||||
<content-with-heading v-if="new_episodes.items.length > 0">
|
||||
<template #heading-left>
|
||||
<p class="title is-4">New episodes</p>
|
||||
<p class="title is-4" v-text="$t('page.podcasts.new-episodes')" />
|
||||
</template>
|
||||
<template #heading-right>
|
||||
<div class="buttons is-centered">
|
||||
<a class="button is-small" @click="mark_all_played">
|
||||
<span class="icon">
|
||||
<mdicon name="pencil" size="16" />
|
||||
</span>
|
||||
<span>Mark All Played</span>
|
||||
<mdicon class="icon" name="pencil" size="16" />
|
||||
<span v-text="$t('page.podcasts.mark-all-played')" />
|
||||
</a>
|
||||
</div>
|
||||
</template>
|
||||
@ -22,25 +20,23 @@
|
||||
/>
|
||||
</template>
|
||||
</content-with-heading>
|
||||
|
||||
<content-with-heading>
|
||||
<template #heading-left>
|
||||
<p class="title is-4">Podcasts</p>
|
||||
<p class="heading">{{ albums.total }} podcasts</p>
|
||||
<p class="title is-4" v-text="$t('page.podcasts.title')" />
|
||||
<p
|
||||
class="heading"
|
||||
v-text="$t('page.podcasts.count', { count: albums.total })"
|
||||
/>
|
||||
</template>
|
||||
<template #heading-right>
|
||||
<div class="buttons is-centered">
|
||||
<a v-if="rss.tracks > 0" class="button is-small" @click="update_rss">
|
||||
<span class="icon">
|
||||
<mdicon name="refresh" size="16" />
|
||||
</span>
|
||||
<span>Update</span>
|
||||
<mdicon class="icon" name="refresh" size="16" />
|
||||
<span v-text="$t('page.podcasts.update')" />
|
||||
</a>
|
||||
<a class="button is-small" @click="open_add_podcast_dialog">
|
||||
<span class="icon">
|
||||
<mdicon name="rss" size="16" />
|
||||
</span>
|
||||
<span>Add Podcast</span>
|
||||
<mdicon class="icon" name="rss" size="16" />
|
||||
<span v-text="$t('page.podcasts.add')" />
|
||||
</a>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -1,8 +1,11 @@
|
||||
<template>
|
||||
<content-with-heading>
|
||||
<template #heading-left>
|
||||
<p class="heading">{{ queue.count }} tracks</p>
|
||||
<p class="title is-4">Queue</p>
|
||||
<p class="title is-4" v-text="$t('page.queue.title')" />
|
||||
<p
|
||||
class="heading"
|
||||
v-text="$t('page.queue.count', { count: queue.count })"
|
||||
/>
|
||||
</template>
|
||||
<template #heading-right>
|
||||
<div class="buttons is-centered">
|
||||
@ -11,32 +14,24 @@
|
||||
:class="{ 'is-info': show_only_next_items }"
|
||||
@click="update_show_next_items"
|
||||
>
|
||||
<span class="icon">
|
||||
<mdicon name="arrow-collapse-down" size="16" />
|
||||
</span>
|
||||
<span>Hide previous</span>
|
||||
<mdicon class="icon" name="arrow-collapse-down" size="16" />
|
||||
<span v-text="$t('page.queue.hide-previous')" />
|
||||
</a>
|
||||
<a class="button is-small" @click="open_add_stream_dialog">
|
||||
<span class="icon">
|
||||
<mdicon name="web" size="16" />
|
||||
</span>
|
||||
<span>Add Stream</span>
|
||||
<mdicon class="icon" name="web" size="16" />
|
||||
<span v-text="$t('page.queue.add-stream')" />
|
||||
</a>
|
||||
<a
|
||||
class="button is-small"
|
||||
:class="{ 'is-info': edit_mode }"
|
||||
@click="edit_mode = !edit_mode"
|
||||
>
|
||||
<span class="icon">
|
||||
<mdicon name="pencil" size="16" />
|
||||
</span>
|
||||
<span>Edit</span>
|
||||
<mdicon class="icon" name="pencil" size="16" />
|
||||
<span v-text="$t('page.queue.edit')" />
|
||||
</a>
|
||||
<a class="button is-small" @click="queue_clear">
|
||||
<span class="icon">
|
||||
<mdicon name="delete-empty" size="16" />
|
||||
</span>
|
||||
<span>Clear</span>
|
||||
<mdicon class="icon" name="delete-empty" size="16" />
|
||||
<span v-text="$t('page.queue.clear')" />
|
||||
</a>
|
||||
<a
|
||||
v-if="is_queue_save_allowed"
|
||||
@ -44,10 +39,8 @@
|
||||
:disabled="queue_items.length === 0"
|
||||
@click="save_dialog"
|
||||
>
|
||||
<span class="icon">
|
||||
<mdicon name="content-save" size="16" />
|
||||
</span>
|
||||
<span>Save</span>
|
||||
<mdicon class="icon" name="content-save" size="16" />
|
||||
<span v-text="$t('page.queue.save')" />
|
||||
</a>
|
||||
</div>
|
||||
</template>
|
||||
@ -68,17 +61,17 @@
|
||||
>
|
||||
<template #actions>
|
||||
<a v-if="!edit_mode" @click.prevent.stop="open_dialog(element)">
|
||||
<span class="icon has-text-dark"
|
||||
><mdicon name="dots-vertical" size="16"
|
||||
/></span>
|
||||
<mdicon
|
||||
class="icon has-text-dark"
|
||||
name="dots-vertical"
|
||||
size="16"
|
||||
/>
|
||||
</a>
|
||||
<a
|
||||
v-if="element.id !== state.item_id && edit_mode"
|
||||
@click.prevent.stop="remove(element)"
|
||||
>
|
||||
<span class="icon has-text-grey"
|
||||
><mdicon name="delete" size="18"
|
||||
/></span>
|
||||
<mdicon class="icon has-text-grey" name="delete" size="18" />
|
||||
</a>
|
||||
</template>
|
||||
</list-item-queue-item>
|
||||
|
@ -2,12 +2,13 @@
|
||||
<div>
|
||||
<content-with-heading>
|
||||
<template #heading-left>
|
||||
<p class="title is-4">Radio</p>
|
||||
<p class="title is-4" v-text="$t('page.radio.title')" />
|
||||
</template>
|
||||
<template #content>
|
||||
<p class="heading has-text-centered-mobile">
|
||||
{{ tracks.total }} tracks
|
||||
</p>
|
||||
<p
|
||||
class="heading has-text-centered-mobile"
|
||||
v-text="$t('page.radio.count', { count: tracks.total })"
|
||||
/>
|
||||
<list-tracks :tracks="tracks.items" />
|
||||
</template>
|
||||
</content-with-heading>
|
||||
|
@ -16,18 +16,10 @@
|
||||
placeholder="Search"
|
||||
autocomplete="off"
|
||||
/>
|
||||
<span class="icon is-left">
|
||||
<mdicon name="magnify" size="16" />
|
||||
</span>
|
||||
<mdicon class="icon is-left" name="magnify" size="16" />
|
||||
</p>
|
||||
<p class="help has-text-centered">
|
||||
Tip: you can search by a smart playlist query language
|
||||
<a
|
||||
href="https://github.com/owntone/owntone-server/blob/master/README_SMARTPL.md"
|
||||
target="_blank"
|
||||
>expression</a
|
||||
>
|
||||
if you prefix it with <code>query:</code>.
|
||||
<span v-html="$t('page.search.help')" />
|
||||
</p>
|
||||
</div>
|
||||
</form>
|
||||
@ -37,20 +29,18 @@
|
||||
:key="recent_search"
|
||||
class="tag"
|
||||
@click="open_recent_search(recent_search)"
|
||||
>{{ recent_search }}</a
|
||||
>
|
||||
v-text="recent_search"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<tabs-search :query="search_query" />
|
||||
|
||||
<!-- Tracks -->
|
||||
<content-with-heading v-if="show_tracks && tracks.total">
|
||||
<template #heading-left>
|
||||
<p class="title is-4">Tracks</p>
|
||||
<p class="title is-4" v-text="$t('page.search.tracks')" />
|
||||
</template>
|
||||
<template #content>
|
||||
<list-tracks :tracks="tracks.items" />
|
||||
@ -61,22 +51,25 @@
|
||||
<a
|
||||
class="button is-light is-small is-rounded"
|
||||
@click="open_search_tracks"
|
||||
>Show all {{ tracks.total.toLocaleString() }} tracks</a
|
||||
>
|
||||
v-text="
|
||||
$t('page.search.show.tracks', {
|
||||
count: tracks.total.toLocaleString()
|
||||
})
|
||||
"
|
||||
/>
|
||||
</p>
|
||||
</nav>
|
||||
</template>
|
||||
</content-with-heading>
|
||||
<content-text v-if="show_tracks && !tracks.total" class="mt-6">
|
||||
<template #content>
|
||||
<p><i>No tracks found</i></p>
|
||||
<p><i v-text="$t('page.search.no-tracks')" /></p>
|
||||
</template>
|
||||
</content-text>
|
||||
|
||||
<!-- Artists -->
|
||||
<content-with-heading v-if="show_artists && artists.total">
|
||||
<template #heading-left>
|
||||
<p class="title is-4">Artists</p>
|
||||
<p class="title is-4" v-text="$t('page.search.artists')" />
|
||||
</template>
|
||||
<template #content>
|
||||
<list-artists :artists="artists" :hide_group_title="true" />
|
||||
@ -87,22 +80,25 @@
|
||||
<a
|
||||
class="button is-light is-small is-rounded"
|
||||
@click="open_search_artists"
|
||||
>Show all {{ artists.total.toLocaleString() }} artists</a
|
||||
>
|
||||
v-text="
|
||||
$t('page.search.show.artists', {
|
||||
count: artists.total.toLocaleString()
|
||||
})
|
||||
"
|
||||
/>
|
||||
</p>
|
||||
</nav>
|
||||
</template>
|
||||
</content-with-heading>
|
||||
<content-text v-if="show_artists && !artists.total">
|
||||
<template #content>
|
||||
<p><i>No artists found</i></p>
|
||||
<p><i v-text="$t('page.search.no-artists')" /></p>
|
||||
</template>
|
||||
</content-text>
|
||||
|
||||
<!-- Albums -->
|
||||
<content-with-heading v-if="show_albums && albums.total">
|
||||
<template #heading-left>
|
||||
<p class="title is-4">Albums</p>
|
||||
<p class="title is-4" v-text="$t('page.search.albums')" />
|
||||
</template>
|
||||
<template #content>
|
||||
<list-albums :albums="albums" :hide_group_title="true" />
|
||||
@ -113,22 +109,25 @@
|
||||
<a
|
||||
class="button is-light is-small is-rounded"
|
||||
@click="open_search_albums"
|
||||
>Show all {{ albums.total.toLocaleString() }} albums</a
|
||||
>
|
||||
v-text="
|
||||
$t('page.search.show-albums', {
|
||||
count: albums.total.toLocaleString()
|
||||
})
|
||||
"
|
||||
/>
|
||||
</p>
|
||||
</nav>
|
||||
</template>
|
||||
</content-with-heading>
|
||||
<content-text v-if="show_albums && !albums.total">
|
||||
<template #content>
|
||||
<p><i>No albums found</i></p>
|
||||
<p><i v-text="$t('page.search.no-albums')" /></p>
|
||||
</template>
|
||||
</content-text>
|
||||
|
||||
<!-- Composers -->
|
||||
<content-with-heading v-if="show_composers && composers.total">
|
||||
<template #heading-left>
|
||||
<p class="title is-4">Composers</p>
|
||||
<p class="title is-4" v-text="$t('page.search.composers')" />
|
||||
</template>
|
||||
<template #content>
|
||||
<list-composers :composers="composers" />
|
||||
@ -139,22 +138,25 @@
|
||||
<a
|
||||
class="button is-light is-small is-rounded"
|
||||
@click="open_search_composers"
|
||||
>Show all {{ composers.total.toLocaleString() }} composers</a
|
||||
>
|
||||
v-text="
|
||||
$t('page.search.show.composers', {
|
||||
count: composers.total.toLocaleString()
|
||||
})
|
||||
"
|
||||
/>
|
||||
</p>
|
||||
</nav>
|
||||
</template>
|
||||
</content-with-heading>
|
||||
<content-text v-if="show_composers && !composers.total">
|
||||
<template #content>
|
||||
<p><i>No composers found</i></p>
|
||||
<p><i v-text="$t('page.search.no-composers')" /></p>
|
||||
</template>
|
||||
</content-text>
|
||||
|
||||
<!-- Playlists -->
|
||||
<content-with-heading v-if="show_playlists && playlists.total">
|
||||
<template #heading-left>
|
||||
<p class="title is-4">Playlists</p>
|
||||
<p class="title is-4" v-text="$t('page.search.playlists')" />
|
||||
</template>
|
||||
<template #content>
|
||||
<list-playlists :playlists="playlists" />
|
||||
@ -165,22 +167,25 @@
|
||||
<a
|
||||
class="button is-light is-small is-rounded"
|
||||
@click="open_search_playlists"
|
||||
>Show all {{ playlists.total.toLocaleString() }} playlists</a
|
||||
>
|
||||
v-text="
|
||||
$t('page.search.show.playlists', {
|
||||
count: playlists.total.toLocaleString()
|
||||
})
|
||||
"
|
||||
/>
|
||||
</p>
|
||||
</nav>
|
||||
</template>
|
||||
</content-with-heading>
|
||||
<content-text v-if="show_playlists && !playlists.total">
|
||||
<template #content>
|
||||
<p><i>No playlists found</i></p>
|
||||
<p><i v-text="$t('page.search.no-playlists')" /></p>
|
||||
</template>
|
||||
</content-text>
|
||||
|
||||
<!-- Podcasts -->
|
||||
<content-with-heading v-if="show_podcasts && podcasts.total">
|
||||
<template #heading-left>
|
||||
<p class="title is-4">Podcasts</p>
|
||||
<p class="title is-4" v-text="$t('page.search.podcasts')" />
|
||||
</template>
|
||||
<template #content>
|
||||
<list-albums :albums="podcasts" />
|
||||
@ -191,22 +196,26 @@
|
||||
<a
|
||||
class="button is-light is-small is-rounded"
|
||||
@click="open_search_podcasts"
|
||||
>Show all {{ podcasts.total.toLocaleString() }} podcasts</a
|
||||
>
|
||||
v-text="
|
||||
$t('page.search.show.podcasts', {
|
||||
count: podcasts.total.toLocaleString()
|
||||
})
|
||||
"
|
||||
/>
|
||||
</p>
|
||||
</nav>
|
||||
</template>
|
||||
</content-with-heading>
|
||||
<content-text v-if="show_podcasts && !podcasts.total">
|
||||
<template #content>
|
||||
<p><i>No podcasts found</i></p>
|
||||
<p><i v-text="$t('page.search.no-podcasts')" /></p>
|
||||
</template>
|
||||
</content-text>
|
||||
|
||||
<!-- Audiobooks -->
|
||||
<content-with-heading v-if="show_audiobooks && audiobooks.total">
|
||||
<template #heading-left>
|
||||
<p class="title is-4">Audiobooks</p>
|
||||
<p class="title is-4" v-text="$t('page.search.audiobooks')" />
|
||||
</template>
|
||||
<template #content>
|
||||
<list-albums :albums="audiobooks" />
|
||||
@ -217,15 +226,19 @@
|
||||
<a
|
||||
class="button is-light is-small is-rounded"
|
||||
@click="open_search_audiobooks"
|
||||
>Show all {{ audiobooks.total.toLocaleString() }} audiobooks</a
|
||||
>
|
||||
v-text="
|
||||
$t('page.search.show.audiobooks', {
|
||||
count: audiobooks.total.toLocaleString()
|
||||
})
|
||||
"
|
||||
/>
|
||||
</p>
|
||||
</nav>
|
||||
</template>
|
||||
</content-with-heading>
|
||||
<content-text v-if="show_audiobooks && !audiobooks.total">
|
||||
<template #content>
|
||||
<p><i>No audiobooks found</i></p>
|
||||
<p><i v-text="$t('page.search.no-audiobooks')" /></p>
|
||||
</template>
|
||||
</content-text>
|
||||
</div>
|
||||
@ -260,7 +273,6 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
search_query: '',
|
||||
|
||||
tracks: { items: [], total: 0 },
|
||||
artists: new GroupByList(),
|
||||
albums: new GroupByList(),
|
||||
|
@ -1,39 +1,40 @@
|
||||
<template>
|
||||
<div class="fd-page-with-tabs">
|
||||
<tabs-settings />
|
||||
|
||||
<content-with-heading>
|
||||
<template #heading-left>
|
||||
<div class="title is-4">Artwork</div>
|
||||
<div class="title is-4" v-text="$t('page.settings.artwork.artwork')" />
|
||||
</template>
|
||||
|
||||
<template #content>
|
||||
<div class="content">
|
||||
<p>
|
||||
OwnTone 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>
|
||||
<div
|
||||
class="content"
|
||||
v-text="$t('page.settings.artwork.explanation-1')"
|
||||
/>
|
||||
<div
|
||||
class="content"
|
||||
v-text="$t('page.settings.artwork.explanation-2')"
|
||||
/>
|
||||
<settings-checkbox
|
||||
v-if="spotify.libspotify_logged_in"
|
||||
category_name="artwork"
|
||||
option_name="use_artwork_source_spotify"
|
||||
>
|
||||
<template #label> Spotify </template>
|
||||
<template #label>
|
||||
<span v-text="$t('page.settings.artwork.spotify')" />
|
||||
<a href="https://www.spotify.com/" target="_blank">
|
||||
<mdicon class="icon" name="open-in-new" size="16" />
|
||||
</a>
|
||||
</template>
|
||||
</settings-checkbox>
|
||||
<settings-checkbox
|
||||
category_name="artwork"
|
||||
option_name="use_artwork_source_discogs"
|
||||
>
|
||||
<template #label>
|
||||
Discogs (<a href="https://www.discogs.com/"
|
||||
>https://www.discogs.com/</a
|
||||
>)
|
||||
<span v-text="$t('page.settings.artwork.discogs')" />
|
||||
<a href="https://www.discogs.com/" target="_blank">
|
||||
<mdicon class="icon" name="open-in-new" size="16" />
|
||||
</a>
|
||||
</template>
|
||||
</settings-checkbox>
|
||||
<settings-checkbox
|
||||
@ -41,9 +42,10 @@
|
||||
option_name="use_artwork_source_coverartarchive"
|
||||
>
|
||||
<template #label>
|
||||
Cover Art Archive (<a href="https://coverartarchive.org/"
|
||||
>https://coverartarchive.org/</a
|
||||
>)
|
||||
<span v-text="$t('page.settings.artwork.coverartarchive')" />
|
||||
<a href="https://coverartarchive.org/" target="_blank">
|
||||
<mdicon class="icon" name="open-in-new" size="16" />
|
||||
</a>
|
||||
</template>
|
||||
</settings-checkbox>
|
||||
</template>
|
||||
|
@ -1,38 +1,33 @@
|
||||
<template>
|
||||
<div class="fd-page-with-tabs">
|
||||
<tabs-settings />
|
||||
|
||||
<content-with-heading>
|
||||
<template #heading-left>
|
||||
<div class="title is-4">Spotify</div>
|
||||
<div
|
||||
class="title is-4"
|
||||
v-text="$t('page.settings.services.spotify.title')"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<template #content>
|
||||
<div v-if="!spotify.spotify_installed" class="notification is-size-7">
|
||||
<p>
|
||||
OwnTone was either built without support for Spotify or libspotify
|
||||
is not installed.
|
||||
</p>
|
||||
<p v-text="$t('page.settings.services.spotify.no-support')" />
|
||||
</div>
|
||||
<div v-if="spotify.spotify_installed">
|
||||
<div class="notification is-size-7">
|
||||
<b>You must have a Spotify premium account</b>.
|
||||
<span v-if="use_libspotity"
|
||||
>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.</span
|
||||
>
|
||||
<b v-text="$t('page.settings.services.spotify.requirements')" />
|
||||
<span
|
||||
v-if="use_libspotity"
|
||||
v-text="$t('page.settings.services.spotify.help')"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div v-if="use_libspotity">
|
||||
<p class="content">
|
||||
<b>libspotify</b> - Login with your Spotify username and password
|
||||
<b v-text="$t('page.settings.services.spotify')" />
|
||||
<span v-text="$t('page.settings.services.spotify.credentials')" />
|
||||
</p>
|
||||
<p v-if="spotify.libspotify_logged_in" class="fd-has-margin-bottom">
|
||||
Logged in as
|
||||
<b
|
||||
><code>{{ spotify.libspotify_user }}</code></b
|
||||
>
|
||||
<span v-text="$t('page.settings.services.spotify.logged-as')" />
|
||||
<b><code v-text="spotify.libspotify_user" /></b>
|
||||
</p>
|
||||
<form
|
||||
v-if="spotify.spotify_installed && !spotify.libspotify_logged_in"
|
||||
@ -46,9 +41,7 @@
|
||||
type="text"
|
||||
placeholder="Username"
|
||||
/>
|
||||
<p class="help is-danger">
|
||||
{{ libspotify.errors.user }}
|
||||
</p>
|
||||
<p class="help is-danger" v-text="libspotify.errors.user" />
|
||||
</div>
|
||||
<div class="control is-expanded">
|
||||
<input
|
||||
@ -57,44 +50,41 @@
|
||||
type="password"
|
||||
placeholder="Password"
|
||||
/>
|
||||
<p class="help is-danger">
|
||||
{{ libspotify.errors.password }}
|
||||
</p>
|
||||
<p
|
||||
class="help is-danger"
|
||||
v-text="libspotify.errors.password"
|
||||
/>
|
||||
</div>
|
||||
<div class="control">
|
||||
<button class="button is-info">Login</button>
|
||||
<button
|
||||
class="button is-info"
|
||||
v-text="$t('page.settings.services.login')"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<p class="help is-danger">
|
||||
{{ libspotify.errors.error }}
|
||||
</p>
|
||||
<p class="help">
|
||||
libspotify enables OwnTone to play Spotify tracks.
|
||||
</p>
|
||||
<p class="help">
|
||||
OwnTone will not store your password, but will still be able to
|
||||
log you in automatically afterwards, because libspotify saves a
|
||||
login token.
|
||||
</p>
|
||||
<p class="help is-danger" v-text="libspotify.errors.error" />
|
||||
<p
|
||||
class="help"
|
||||
v-text="$t('page.settings.services.spotify.help-1')"
|
||||
/>
|
||||
<p
|
||||
class="help"
|
||||
v-text="$t('page.settings.services.spotify.help-2')"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="fd-has-margin-top">
|
||||
<p class="content">
|
||||
<b>Spotify Web API</b> - Grant access to the Spotify Web API
|
||||
</p>
|
||||
<p
|
||||
class="content"
|
||||
v-html="$t('page.settings.services.spotify.grant-access')"
|
||||
/>
|
||||
<p v-if="spotify.webapi_token_valid">
|
||||
Access granted for
|
||||
<b
|
||||
><code>{{ spotify.webapi_user }}</code></b
|
||||
>
|
||||
<span v-text="$t('page.settings.services.spotify.user')" />
|
||||
<code v-text="spotify.webapi_user" />
|
||||
</p>
|
||||
<p v-if="spotify_missing_scope.length > 0" class="help is-danger">
|
||||
Please reauthorize Web API access to grant OwnTone the following
|
||||
additional access rights:
|
||||
<b
|
||||
><code>{{ spotify_missing_scope.join() }}</code></b
|
||||
>
|
||||
<span v-text="$t('page.settings.services.spotify.reauthorize')" />
|
||||
<code v-text="spotify_missing_scope.join()" />
|
||||
</p>
|
||||
<div class="field fd-has-margin-top">
|
||||
<div class="control">
|
||||
@ -106,45 +96,52 @@
|
||||
spotify_missing_scope.length > 0
|
||||
}"
|
||||
:href="spotify.oauth_uri"
|
||||
>Authorize Web API access</a
|
||||
>
|
||||
v-text="$t('page.settings.services.spotify.authorize')"
|
||||
/>
|
||||
</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
|
||||
>.
|
||||
<span v-text="$t('page.settings.services.spotify.scopes')" />
|
||||
<code v-text="spotify_required_scope.join()" />
|
||||
</p>
|
||||
<div
|
||||
v-if="spotify.webapi_token_valid"
|
||||
class="field fd-has-margin-top"
|
||||
>
|
||||
<div class="control">
|
||||
<a class="button is-danger" @click="logout_spotify">Logout</a>
|
||||
<a
|
||||
class="button is-danger"
|
||||
@click="logout_spotify"
|
||||
v-text="$t('page.settings.services.logout')"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</content-with-heading>
|
||||
|
||||
<content-with-heading>
|
||||
<template #heading-left>
|
||||
<div class="title is-4">Last.fm</div>
|
||||
<div
|
||||
class="title is-4"
|
||||
v-text="$t('page.settings.services.lastfm.title')"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<template #content>
|
||||
<div v-if="!lastfm.enabled" class="notification is-size-7">
|
||||
<p>OwnTone was built without support for Last.fm.</p>
|
||||
<p v-text="$t('page.settings.services.lastfm.no-support')" />
|
||||
</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>
|
||||
<p
|
||||
class="content"
|
||||
v-html="$t('page.settings.services.lastfm.grant-access')"
|
||||
/>
|
||||
<div v-if="lastfm.scrobbling_enabled">
|
||||
<a class="button" @click="logoutLastfm">Stop scrobbling</a>
|
||||
<a
|
||||
class="button"
|
||||
@click="logoutLastfm"
|
||||
v-text="$t('page.settings.services.lastfm.stop-scrobbling')"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="!lastfm.scrobbling_enabled">
|
||||
<form @submit.prevent="login_lastfm">
|
||||
@ -156,9 +153,7 @@
|
||||
type="text"
|
||||
placeholder="Username"
|
||||
/>
|
||||
<p class="help is-danger">
|
||||
{{ lastfm_login.errors.user }}
|
||||
</p>
|
||||
<p class="help is-danger" v-text="lastfm_login.errors.user" />
|
||||
</div>
|
||||
<div class="control is-expanded">
|
||||
<input
|
||||
@ -167,21 +162,24 @@
|
||||
type="password"
|
||||
placeholder="Password"
|
||||
/>
|
||||
<p class="help is-danger">
|
||||
{{ lastfm_login.errors.password }}
|
||||
</p>
|
||||
<p
|
||||
class="help is-danger"
|
||||
v-text="lastfm_login.errors.password"
|
||||
/>
|
||||
</div>
|
||||
<div class="control">
|
||||
<button class="button is-info" type="submit">Login</button>
|
||||
<button
|
||||
class="button is-info"
|
||||
type="submit"
|
||||
v-text="$t('page.settings.services.login')"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<p class="help is-danger">
|
||||
{{ lastfm_login.errors.error }}
|
||||
</p>
|
||||
<p class="help">
|
||||
OwnTone will not store your Last.fm username/password, only the
|
||||
session key. The session key does not expire.
|
||||
</p>
|
||||
<p class="help is-danger" v-text="lastfm_login.errors.error" />
|
||||
<p
|
||||
class="help"
|
||||
v-text="$t('page.settings.services.lastfm.info')"
|
||||
/>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,18 +1,17 @@
|
||||
<template>
|
||||
<div class="fd-page-with-tabs">
|
||||
<tabs-settings />
|
||||
|
||||
<content-with-heading>
|
||||
<template #heading-left>
|
||||
<div class="title is-4">Remote Pairing</div>
|
||||
<div class="title is-4" v-text="$t('page.settings.devices.pairing')" />
|
||||
</template>
|
||||
|
||||
<template #content>
|
||||
<!-- Paring request active -->
|
||||
<div v-if="pairing.active" class="notification">
|
||||
<form @submit.prevent="kickoff_pairing">
|
||||
<label class="label has-text-weight-normal">
|
||||
Remote pairing request from <b>{{ pairing.remote }}</b>
|
||||
<span v-text="$t('page.settings.devices.pairing-request')" />
|
||||
<b v-text="pairing.remote" />
|
||||
</label>
|
||||
<div class="field is-grouped">
|
||||
<div class="control">
|
||||
@ -24,29 +23,33 @@
|
||||
/>
|
||||
</div>
|
||||
<div class="control">
|
||||
<button class="button is-info" type="submit">Send</button>
|
||||
<button
|
||||
class="button is-info"
|
||||
type="submit"
|
||||
v-text="$t('page.settings.devices.send')"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<!-- No pairing requests -->
|
||||
<div v-if="!pairing.active" class="content">
|
||||
<p>No active pairing request.</p>
|
||||
<p v-text="$t('page.settings.devices.no-active-pairing')" />
|
||||
</div>
|
||||
</template>
|
||||
</content-with-heading>
|
||||
|
||||
<content-with-heading>
|
||||
<template #heading-left>
|
||||
<div class="title is-4">Speaker pairing and device verification</div>
|
||||
<div
|
||||
class="title is-4"
|
||||
v-text="$t('page.settings.devices.speaker-pairing')"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<template #content>
|
||||
<p class="content">
|
||||
If your speaker requires pairing then activate it below and enter the
|
||||
PIN that it displays.
|
||||
</p>
|
||||
|
||||
<p
|
||||
class="content"
|
||||
v-text="$t('page.settings.devices.speaker-pairing-info')"
|
||||
/>
|
||||
<div v-for="output in outputs" :key="output.id">
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
@ -54,9 +57,10 @@
|
||||
<input
|
||||
v-model="output.selected"
|
||||
type="checkbox"
|
||||
style="margin-right: 5px"
|
||||
@change="output_toggle(output.id)"
|
||||
/>
|
||||
{{ output.name }}
|
||||
<span v-text="output.name" />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
@ -71,11 +75,15 @@
|
||||
v-model="verification_req.pin"
|
||||
class="input"
|
||||
type="text"
|
||||
placeholder="Enter verification code"
|
||||
:placeholder="$t('page.settings.devices.verification-code')"
|
||||
/>
|
||||
</div>
|
||||
<div class="control">
|
||||
<button class="button is-info" type="submit">Verify</button>
|
||||
<button
|
||||
class="button is-info"
|
||||
type="submit"
|
||||
v-text="$t('page.settings.devices.verify')"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
@ -1,92 +1,123 @@
|
||||
<template>
|
||||
<div class="fd-page-with-tabs">
|
||||
<tabs-settings />
|
||||
|
||||
<content-with-heading>
|
||||
<template #heading-left>
|
||||
<div class="title is-4">Navbar items</div>
|
||||
<div class="title is-4" v-text="$t('page.settings.general.language')" />
|
||||
</template>
|
||||
|
||||
<template #content>
|
||||
<p class="content">Select the top navigation bar menu items</p>
|
||||
<div class="notification is-size-7">
|
||||
If you select more items than can be shown on your screen then the
|
||||
burger menu will disappear.
|
||||
</div>
|
||||
<dropdown-menu v-model="locale" :options="locales" />
|
||||
</template>
|
||||
</content-with-heading>
|
||||
<content-with-heading>
|
||||
<template #heading-left>
|
||||
<div
|
||||
class="title is-4"
|
||||
v-text="$t('page.settings.general.navigation-items')"
|
||||
/>
|
||||
</template>
|
||||
<template #content>
|
||||
<p
|
||||
class="content"
|
||||
v-text="$t('page.settings.general.navigation-item-selection')"
|
||||
/>
|
||||
<div
|
||||
class="notification is-size-7"
|
||||
v-text="$t('page.settings.general.navigation-item-selection-info')"
|
||||
/>
|
||||
<settings-checkbox
|
||||
category_name="webinterface"
|
||||
option_name="show_menu_item_playlists"
|
||||
>
|
||||
<template #label> Playlists </template>
|
||||
<template #label>
|
||||
<span v-text="$t('page.settings.general.playlists')" />
|
||||
</template>
|
||||
</settings-checkbox>
|
||||
<settings-checkbox
|
||||
category_name="webinterface"
|
||||
option_name="show_menu_item_music"
|
||||
>
|
||||
<template #label> Music </template>
|
||||
<template #label>
|
||||
<span v-text="$t('page.settings.general.music')" />
|
||||
</template>
|
||||
</settings-checkbox>
|
||||
<settings-checkbox
|
||||
category_name="webinterface"
|
||||
option_name="show_menu_item_podcasts"
|
||||
>
|
||||
<template #label> Podcasts </template>
|
||||
<template #label>
|
||||
<span v-text="$t('page.settings.general.podcasts')" />
|
||||
</template>
|
||||
</settings-checkbox>
|
||||
<settings-checkbox
|
||||
category_name="webinterface"
|
||||
option_name="show_menu_item_audiobooks"
|
||||
>
|
||||
<template #label> Audiobooks </template>
|
||||
<template #label>
|
||||
<span v-text="$t('page.settings.general.audiobooks')" />
|
||||
</template>
|
||||
</settings-checkbox>
|
||||
<settings-checkbox
|
||||
category_name="webinterface"
|
||||
option_name="show_menu_item_radio"
|
||||
>
|
||||
<template #label> Radio </template>
|
||||
<template #label>
|
||||
<span v-text="$t('page.settings.general.radio')" />
|
||||
</template>
|
||||
</settings-checkbox>
|
||||
<settings-checkbox
|
||||
category_name="webinterface"
|
||||
option_name="show_menu_item_files"
|
||||
>
|
||||
<template #label> Files </template>
|
||||
<template #label>
|
||||
<span v-text="$t('page.settings.general.files')" />
|
||||
</template>
|
||||
</settings-checkbox>
|
||||
<settings-checkbox
|
||||
category_name="webinterface"
|
||||
option_name="show_menu_item_search"
|
||||
>
|
||||
<template #label> Search </template>
|
||||
<template #label>
|
||||
<span v-text="$t('page.settings.general.search')" />
|
||||
</template>
|
||||
</settings-checkbox>
|
||||
</template>
|
||||
</content-with-heading>
|
||||
|
||||
<content-with-heading>
|
||||
<template #heading-left>
|
||||
<div class="title is-4">Album lists</div>
|
||||
<div
|
||||
class="title is-4"
|
||||
v-text="$t('page.settings.general.album-lists')"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<template #content>
|
||||
<settings-checkbox
|
||||
category_name="webinterface"
|
||||
option_name="show_cover_artwork_in_album_lists"
|
||||
>
|
||||
<template #label> Show cover artwork in album list </template>
|
||||
<template #label>
|
||||
<span v-text="$t('page.settings.general.show-coverart')" />
|
||||
</template>
|
||||
</settings-checkbox>
|
||||
</template>
|
||||
</content-with-heading>
|
||||
|
||||
<content-with-heading>
|
||||
<template #heading-left>
|
||||
<div class="title is-4">Now playing page</div>
|
||||
<div
|
||||
class="title is-4"
|
||||
v-text="$t('page.settings.general.now-playing-page')"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<template #content>
|
||||
<settings-checkbox
|
||||
category_name="webinterface"
|
||||
option_name="show_composer_now_playing"
|
||||
>
|
||||
<template #label> Show composer </template>
|
||||
<template #label>
|
||||
<span v-text="$t('page.settings.general.show-composer')" />
|
||||
</template>
|
||||
<template #info>
|
||||
If enabled the composer of the current playing track is shown on the
|
||||
"now playing page"
|
||||
<span v-text="$t('page.settings.general.show-composer-info')" />
|
||||
</template>
|
||||
</settings-checkbox>
|
||||
<settings-textfield
|
||||
@ -95,36 +126,42 @@
|
||||
:disabled="!settings_option_show_composer_now_playing"
|
||||
placeholder="Genres"
|
||||
>
|
||||
<template #label> Show composer only for listed genres </template>
|
||||
<template #label>
|
||||
<span v-text="$t('page.settings.general.show-composer-genres')" />
|
||||
</template>
|
||||
<template #info>
|
||||
<p class="help">
|
||||
Comma separated list of genres the composer should be displayed on
|
||||
the "now playing page".
|
||||
</p>
|
||||
<p class="help">Leave empty to always show the composer.</p>
|
||||
<p class="help">
|
||||
The genre tag of the current track is matched by checking, if one
|
||||
of the defined genres are included. For example setting to
|
||||
<code>classical, soundtrack</code> will show the composer for
|
||||
tracks with a genre tag of "Contemporary Classical".<br />
|
||||
</p>
|
||||
<p
|
||||
class="help"
|
||||
v-text="$t('page.settings.general.show-composer-genres-info-1')"
|
||||
/>
|
||||
<p
|
||||
class="help"
|
||||
v-text="$t('page.settings.general.show-composer-genres-info-2')"
|
||||
/>
|
||||
<p
|
||||
class="help"
|
||||
v-text="$t('page.settings.general.show-composer-genres-info-3')"
|
||||
/>
|
||||
</template>
|
||||
</settings-textfield>
|
||||
</template>
|
||||
</content-with-heading>
|
||||
|
||||
<content-with-heading>
|
||||
<template #heading-left>
|
||||
<div class="title is-4">Recently added page</div>
|
||||
<div
|
||||
class="title is-4"
|
||||
v-text="$t('page.settings.general.recently-added-page')"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<template #content>
|
||||
<settings-intfield
|
||||
category_name="webinterface"
|
||||
option_name="recently_added_limit"
|
||||
>
|
||||
<template #label>
|
||||
Limit the number of albums shown on the "Recently Added" page
|
||||
<span
|
||||
v-text="$t('page.settings.general.recently-added-page-info')"
|
||||
/>
|
||||
</template>
|
||||
</settings-intfield>
|
||||
</template>
|
||||
@ -138,6 +175,7 @@ import TabsSettings from '@/components/TabsSettings.vue'
|
||||
import SettingsCheckbox from '@/components/SettingsCheckbox.vue'
|
||||
import SettingsTextfield from '@/components/SettingsTextfield.vue'
|
||||
import SettingsIntfield from '@/components/SettingsIntfield.vue'
|
||||
import DropdownMenu from '@/components/DropdownMenu.vue'
|
||||
|
||||
export default {
|
||||
name: 'SettingsPageWebinterface',
|
||||
@ -146,12 +184,28 @@ export default {
|
||||
TabsSettings,
|
||||
SettingsCheckbox,
|
||||
SettingsTextfield,
|
||||
SettingsIntfield
|
||||
SettingsIntfield,
|
||||
DropdownMenu
|
||||
},
|
||||
|
||||
computed: {
|
||||
settings_option_show_composer_now_playing() {
|
||||
return this.$store.getters.settings_option_show_composer_now_playing
|
||||
},
|
||||
locale: {
|
||||
get() {
|
||||
return this.$i18n.locale
|
||||
},
|
||||
set(locale) {
|
||||
this.$i18n.locale = locale
|
||||
}
|
||||
},
|
||||
locales: {
|
||||
get() {
|
||||
return this.$i18n.availableLocales.map((item) => {
|
||||
return { id: item, name: this.$t('language.' + item) }
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,29 +1,27 @@
|
||||
<template>
|
||||
<content-with-hero>
|
||||
<template #heading-left>
|
||||
<h1 class="title is-5">
|
||||
{{ album.name }}
|
||||
</h1>
|
||||
<h1 class="title is-5" v-text="album.name" />
|
||||
<h2 class="subtitle is-6 has-text-link has-text-weight-normal">
|
||||
<a class="has-text-link" @click="open_artist">{{
|
||||
album.artists[0].name
|
||||
}}</a>
|
||||
<a
|
||||
class="has-text-link"
|
||||
@click="open_artist"
|
||||
v-text="album.artists[0].name"
|
||||
/>
|
||||
</h2>
|
||||
|
||||
<div class="buttons fd-is-centered-mobile fd-has-margin-top">
|
||||
<a class="button is-small is-dark is-rounded" @click="play">
|
||||
<span class="icon"><mdicon name="shuffle" size="16" /></span>
|
||||
<span>Shuffle</span>
|
||||
<mdicon class="icon" name="shuffle" size="16" />
|
||||
<span v-text="$t('page.spotify.album.shuffle')" />
|
||||
</a>
|
||||
<a
|
||||
class="button is-small is-light is-rounded"
|
||||
@click="show_album_details_modal = true"
|
||||
>
|
||||
<span class="icon"><mdicon name="dots-horizontal" size="16" /></span>
|
||||
<mdicon class="icon" name="dots-horizontal" size="16" />
|
||||
</a>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #heading-right>
|
||||
<p class="image is-square fd-has-shadow fd-has-action">
|
||||
<cover-artwork
|
||||
@ -34,11 +32,13 @@
|
||||
/>
|
||||
</p>
|
||||
</template>
|
||||
|
||||
<template #content>
|
||||
<p class="heading is-7 has-text-centered-mobile fd-has-margin-top">
|
||||
{{ album.tracks.total }} tracks
|
||||
</p>
|
||||
<p
|
||||
class="heading is-7 has-text-centered-mobile fd-has-margin-top"
|
||||
v-text="
|
||||
$t('page.spotify.album.track-count', { count: album.tracks.total })
|
||||
"
|
||||
/>
|
||||
<spotify-list-item-track
|
||||
v-for="(track, index) in album.tracks.items"
|
||||
:key="track.id"
|
||||
@ -49,9 +49,7 @@
|
||||
>
|
||||
<template #actions>
|
||||
<a @click.prevent.stop="open_track_dialog(track)">
|
||||
<span class="icon has-text-dark"
|
||||
><mdicon name="dots-vertical" size="16"
|
||||
/></span>
|
||||
<mdicon class="icon has-text-dark" name="dots-vertical" size="16" />
|
||||
</a>
|
||||
</template>
|
||||
</spotify-list-item-track>
|
||||
|
@ -1,9 +1,7 @@
|
||||
<template>
|
||||
<content-with-heading>
|
||||
<template #heading-left>
|
||||
<p class="title is-4">
|
||||
{{ artist.name }}
|
||||
</p>
|
||||
<p class="title is-4" v-text="artist.name" />
|
||||
</template>
|
||||
<template #heading-right>
|
||||
<div class="buttons is-centered">
|
||||
@ -11,16 +9,19 @@
|
||||
class="button is-small is-light is-rounded"
|
||||
@click="show_artist_details_modal = true"
|
||||
>
|
||||
<span class="icon"><mdicon name="dots-horizontal" size="16" /></span>
|
||||
<mdicon class="icon" name="dots-horizontal" size="16" />
|
||||
</a>
|
||||
<a class="button is-small is-dark is-rounded" @click="play">
|
||||
<span class="icon"><mdicon name="shuffle" size="16" /></span>
|
||||
<span>Shuffle</span>
|
||||
<mdicon class="icon" name="shuffle" size="16" />
|
||||
<span v-text="$t('page.spotify.artist.shuffle')" />
|
||||
</a>
|
||||
</div>
|
||||
</template>
|
||||
<template #content>
|
||||
<p class="heading has-text-centered-mobile">{{ total }} albums</p>
|
||||
<p
|
||||
class="heading has-text-centered-mobile"
|
||||
v-text="$t('page.spotify.artist.album-count', { count: total })"
|
||||
/>
|
||||
<spotify-list-item-album
|
||||
v-for="album in albums"
|
||||
:key="album.id"
|
||||
@ -40,9 +41,7 @@
|
||||
</template>
|
||||
<template #actions>
|
||||
<a @click.prevent.stop="open_dialog(album)">
|
||||
<span class="icon has-text-dark"
|
||||
><mdicon name="dots-vertical" size="16"
|
||||
/></span>
|
||||
<mdicon class="icon has-text-dark" name="dots-vertical" size="16" />
|
||||
</a>
|
||||
</template>
|
||||
</spotify-list-item-album>
|
||||
|
@ -1,11 +1,10 @@
|
||||
<template>
|
||||
<div class="fd-page-with-tabs">
|
||||
<tabs-music />
|
||||
|
||||
<!-- New Releases -->
|
||||
<content-with-heading>
|
||||
<template #heading-left>
|
||||
<p class="title is-4">New Releases</p>
|
||||
<p class="title is-4" v-text="$t('page.spotify.browse.new-releases')" />
|
||||
</template>
|
||||
<template #content>
|
||||
<spotify-list-item-album
|
||||
@ -27,9 +26,11 @@
|
||||
</template>
|
||||
<template #actions>
|
||||
<a @click.prevent.stop="open_album_dialog(album)">
|
||||
<span class="icon has-text-dark"
|
||||
><mdicon name="dots-vertical" size="16"
|
||||
/></span>
|
||||
<mdicon
|
||||
class="icon has-text-dark"
|
||||
name="dots-vertical"
|
||||
size="16"
|
||||
/>
|
||||
</a>
|
||||
</template>
|
||||
</spotify-list-item-album>
|
||||
@ -45,18 +46,19 @@
|
||||
<router-link
|
||||
to="/music/spotify/new-releases"
|
||||
class="button is-light is-small is-rounded"
|
||||
>
|
||||
Show more
|
||||
</router-link>
|
||||
v-text="$t('page.spotify.browse.show-more')"
|
||||
/>
|
||||
</p>
|
||||
</nav>
|
||||
</template>
|
||||
</content-with-heading>
|
||||
|
||||
<!-- Featured Playlists -->
|
||||
<content-with-heading>
|
||||
<template #heading-left>
|
||||
<p class="title is-4">Featured Playlists</p>
|
||||
<p
|
||||
class="title is-4"
|
||||
v-text="$t('page.spotify.browse.featured-playlists')"
|
||||
/>
|
||||
</template>
|
||||
<template #content>
|
||||
<spotify-list-item-playlist
|
||||
@ -66,9 +68,11 @@
|
||||
>
|
||||
<template #actions>
|
||||
<a @click.prevent.stop="open_playlist_dialog(playlist)">
|
||||
<span class="icon has-text-dark"
|
||||
><mdicon name="dots-vertical" size="16"
|
||||
/></span>
|
||||
<mdicon
|
||||
class="icon has-text-dark"
|
||||
name="dots-vertical"
|
||||
size="16"
|
||||
/>
|
||||
</a>
|
||||
</template>
|
||||
</spotify-list-item-playlist>
|
||||
@ -84,9 +88,8 @@
|
||||
<router-link
|
||||
to="/music/spotify/featured-playlists"
|
||||
class="button is-light is-small is-rounded"
|
||||
>
|
||||
Show more
|
||||
</router-link>
|
||||
v-text="$t('page.spotify.browse.show-more')"
|
||||
/>
|
||||
</p>
|
||||
</nav>
|
||||
</template>
|
||||
|
@ -1,7 +1,6 @@
|
||||
<template>
|
||||
<div class="fd-page-with-tabs">
|
||||
<tabs-music />
|
||||
|
||||
<content-with-heading>
|
||||
<template #heading-left>
|
||||
<p class="title is-4">Featured Playlists</p>
|
||||
@ -14,9 +13,11 @@
|
||||
>
|
||||
<template #actions>
|
||||
<a @click.prevent.stop="open_playlist_dialog(playlist)">
|
||||
<span class="icon has-text-dark"
|
||||
><mdicon name="dots-vertical" size="16"
|
||||
/></span>
|
||||
<mdicon
|
||||
class="icon has-text-dark"
|
||||
name="dots-vertical"
|
||||
size="16"
|
||||
/>
|
||||
</a>
|
||||
</template>
|
||||
</spotify-list-item-playlist>
|
||||
|
@ -1,7 +1,6 @@
|
||||
<template>
|
||||
<div class="fd-page-with-tabs">
|
||||
<tabs-music />
|
||||
|
||||
<content-with-heading>
|
||||
<template #heading-left>
|
||||
<p class="title is-4">New Releases</p>
|
||||
@ -26,9 +25,11 @@
|
||||
</template>
|
||||
<template #actions>
|
||||
<a @click.prevent.stop="open_album_dialog(album)">
|
||||
<span class="icon has-text-dark"
|
||||
><mdicon name="dots-vertical" size="16"
|
||||
/></span>
|
||||
<mdicon
|
||||
class="icon has-text-dark"
|
||||
name="dots-vertical"
|
||||
size="16"
|
||||
/>
|
||||
</a>
|
||||
</template>
|
||||
</spotify-list-item-album>
|
||||
|
@ -1,9 +1,7 @@
|
||||
<template>
|
||||
<content-with-heading>
|
||||
<template #heading-left>
|
||||
<div class="title is-4">
|
||||
{{ playlist.name }}
|
||||
</div>
|
||||
<div class="title is-4" v-text="playlist.name" />
|
||||
</template>
|
||||
<template #heading-right>
|
||||
<div class="buttons is-centered">
|
||||
@ -11,18 +9,21 @@
|
||||
class="button is-small is-light is-rounded"
|
||||
@click="show_playlist_details_modal = true"
|
||||
>
|
||||
<span class="icon"><mdicon name="dots-horizontal" size="16" /></span>
|
||||
<mdicon class="icon" name="dots-horizontal" size="16" />
|
||||
</a>
|
||||
<a class="button is-small is-dark is-rounded" @click="play">
|
||||
<span class="icon"><mdicon name="shuffle" size="16" /></span>
|
||||
<span>Shuffle</span>
|
||||
<mdicon class="icon" name="shuffle" size="16" />
|
||||
<span v-text="$t('page.spotify.playlist.shuffle')" />
|
||||
</a>
|
||||
</div>
|
||||
</template>
|
||||
<template #content>
|
||||
<p class="heading has-text-centered-mobile">
|
||||
{{ playlist.tracks.total }} tracks
|
||||
</p>
|
||||
<p
|
||||
class="heading has-text-centered-mobile"
|
||||
v-text="
|
||||
$t('page.spotify.playlist.count', { count: playlist.tracks.total })
|
||||
"
|
||||
/>
|
||||
<spotify-list-item-track
|
||||
v-for="(item, index) in tracks"
|
||||
:key="item.track.id"
|
||||
@ -33,9 +34,7 @@
|
||||
>
|
||||
<template #actions>
|
||||
<a @click.prevent.stop="open_track_dialog(item.track)">
|
||||
<span class="icon has-text-dark"
|
||||
><mdicon name="dots-vertical" size="16"
|
||||
/></span>
|
||||
<mdicon class="icon has-text-dark" name="dots-vertical" size="16" />
|
||||
</a>
|
||||
</template>
|
||||
</spotify-list-item-track>
|
||||
|
@ -16,9 +16,7 @@
|
||||
placeholder="Search"
|
||||
autocomplete="off"
|
||||
/>
|
||||
<span class="icon is-left">
|
||||
<mdicon name="magnify" size="16" />
|
||||
</span>
|
||||
<mdicon class="icon is-left" name="magnify" size="16" />
|
||||
</p>
|
||||
</div>
|
||||
</form>
|
||||
@ -28,20 +26,18 @@
|
||||
:key="recent_search"
|
||||
class="tag"
|
||||
@click="open_recent_search(recent_search)"
|
||||
>{{ recent_search }}</a
|
||||
>
|
||||
v-text="recent_search"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<tabs-search :query="search_query" />
|
||||
|
||||
<!-- Tracks -->
|
||||
<content-with-heading v-if="show_tracks && tracks.total">
|
||||
<template #heading-left>
|
||||
<p class="title is-4">Tracks</p>
|
||||
<p class="title is-4" v-text="$t('page.spotify.search.tracks')" />
|
||||
</template>
|
||||
<template #content>
|
||||
<spotify-list-item-track
|
||||
@ -54,9 +50,11 @@
|
||||
>
|
||||
<template #actions>
|
||||
<a @click.prevent.stop="open_track_dialog(track)">
|
||||
<span class="icon has-text-dark"
|
||||
><mdicon name="dots-vertical" size="16"
|
||||
/></span>
|
||||
<mdicon
|
||||
class="icon has-text-dark"
|
||||
name="dots-vertical"
|
||||
size="16"
|
||||
/>
|
||||
</a>
|
||||
</template>
|
||||
</spotify-list-item-track>
|
||||
@ -79,22 +77,25 @@
|
||||
<a
|
||||
class="button is-light is-small is-rounded"
|
||||
@click="open_search_tracks"
|
||||
>Show all {{ tracks.total.toLocaleString() }} tracks</a
|
||||
>
|
||||
v-text="
|
||||
$t('page.spotify.search.show-all-tracks', {
|
||||
count: tracks.total.toLocaleString()
|
||||
})
|
||||
"
|
||||
/>
|
||||
</p>
|
||||
</nav>
|
||||
</template>
|
||||
</content-with-heading>
|
||||
<content-text v-if="show_tracks && !tracks.total" class="mt-6">
|
||||
<template #content>
|
||||
<p><i>No tracks found</i></p>
|
||||
<p><i v-text="$t('page.spotify.search.no-tracks')" /></p>
|
||||
</template>
|
||||
</content-text>
|
||||
|
||||
<!-- Artists -->
|
||||
<content-with-heading v-if="show_artists && artists.total">
|
||||
<template #heading-left>
|
||||
<p class="title is-4">Artists</p>
|
||||
<p class="title is-4" v-text="$t('page.spotify.search.artists')" />
|
||||
</template>
|
||||
<template #content>
|
||||
<spotify-list-item-artist
|
||||
@ -104,9 +105,11 @@
|
||||
>
|
||||
<template #actions>
|
||||
<a @click.prevent.stop="open_artist_dialog(artist)">
|
||||
<span class="icon has-text-dark"
|
||||
><mdicon name="dots-vertical" size="16"
|
||||
/></span>
|
||||
<mdicon
|
||||
class="icon has-text-dark"
|
||||
name="dots-vertical"
|
||||
size="16"
|
||||
/>
|
||||
</a>
|
||||
</template>
|
||||
</spotify-list-item-artist>
|
||||
@ -128,22 +131,25 @@
|
||||
<a
|
||||
class="button is-light is-small is-rounded"
|
||||
@click="open_search_artists"
|
||||
>Show all {{ artists.total.toLocaleString() }} artists</a
|
||||
>
|
||||
v-text="
|
||||
$t('page.spotify.search.show-all-artists', {
|
||||
count: artists.total.toLocaleString()
|
||||
})
|
||||
"
|
||||
/>
|
||||
</p>
|
||||
</nav>
|
||||
</template>
|
||||
</content-with-heading>
|
||||
<content-text v-if="show_artists && !artists.total">
|
||||
<template #content>
|
||||
<p><i>No artists found</i></p>
|
||||
<p><i v-text="$t('page.spotify.search.no-artists')" /></p>
|
||||
</template>
|
||||
</content-text>
|
||||
|
||||
<!-- Albums -->
|
||||
<content-with-heading v-if="show_albums && albums.total">
|
||||
<template #heading-left>
|
||||
<p class="title is-4">Albums</p>
|
||||
<p class="title is-4" v-text="$t('page.spotify.search.albums')" />
|
||||
</template>
|
||||
<template #content>
|
||||
<spotify-list-item-album
|
||||
@ -165,9 +171,11 @@
|
||||
</template>
|
||||
<template #actions>
|
||||
<a @click.prevent.stop="open_album_dialog(album)">
|
||||
<span class="icon has-text-dark"
|
||||
><mdicon name="dots-vertical" size="16"
|
||||
/></span>
|
||||
<mdicon
|
||||
class="icon has-text-dark"
|
||||
name="dots-vertical"
|
||||
size="16"
|
||||
/>
|
||||
</a>
|
||||
</template>
|
||||
</spotify-list-item-album>
|
||||
@ -189,22 +197,25 @@
|
||||
<a
|
||||
class="button is-light is-small is-rounded"
|
||||
@click="open_search_albums"
|
||||
>Show all {{ albums.total.toLocaleString() }} albums</a
|
||||
>
|
||||
v-text="
|
||||
$t('page.spotify.search.show-all-albums', {
|
||||
count: albums.total.toLocaleString()
|
||||
})
|
||||
"
|
||||
/>
|
||||
</p>
|
||||
</nav>
|
||||
</template>
|
||||
</content-with-heading>
|
||||
<content-text v-if="show_albums && !albums.total">
|
||||
<template #content>
|
||||
<p><i>No albums found</i></p>
|
||||
<p><i v-text="$t('page.spotify.search.no-albums')" /></p>
|
||||
</template>
|
||||
</content-text>
|
||||
|
||||
<!-- Playlists -->
|
||||
<content-with-heading v-if="show_playlists && playlists.total">
|
||||
<template #heading-left>
|
||||
<p class="title is-4">Playlists</p>
|
||||
<p class="title is-4" v-text="$t('page.spotify.search.playlists')" />
|
||||
</template>
|
||||
<template #content>
|
||||
<spotify-list-item-playlist
|
||||
@ -214,9 +225,11 @@
|
||||
>
|
||||
<template #actions>
|
||||
<a @click.prevent.stop="open_playlist_dialog(playlist)">
|
||||
<span class="icon has-text-dark"
|
||||
><mdicon name="dots-vertical" size="16"
|
||||
/></span>
|
||||
<mdicon
|
||||
class="icon has-text-dark"
|
||||
name="dots-vertical"
|
||||
size="16"
|
||||
/>
|
||||
</a>
|
||||
</template>
|
||||
</spotify-list-item-playlist>
|
||||
@ -238,15 +251,19 @@
|
||||
<a
|
||||
class="button is-light is-small is-rounded"
|
||||
@click="open_search_playlists"
|
||||
>Show all {{ playlists.total.toLocaleString() }} playlists</a
|
||||
>
|
||||
v-text="
|
||||
$t('page.spotify.search.show-all-playlists', {
|
||||
count: playlists.total.toLocaleString()
|
||||
})
|
||||
"
|
||||
/>
|
||||
</p>
|
||||
</nav>
|
||||
</template>
|
||||
</content-with-heading>
|
||||
<content-text v-if="show_playlists && !playlists.total">
|
||||
<template #content>
|
||||
<p><i>No playlists found</i></p>
|
||||
<p><i v-text="$t('page.spotify.search.no-playlists')" /></p>
|
||||
</template>
|
||||
</content-text>
|
||||
</div>
|
||||
|
@ -55,9 +55,9 @@ export default createStore({
|
||||
|
||||
hide_singles: false,
|
||||
hide_spotify: false,
|
||||
artists_sort: 'Name',
|
||||
artist_albums_sort: 'Name',
|
||||
albums_sort: 'Name',
|
||||
artists_sort: 1,
|
||||
artist_albums_sort: 1,
|
||||
albums_sort: 1,
|
||||
show_only_next_items: false,
|
||||
show_burger_menu: false,
|
||||
show_player_menu: false,
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user