mirror of
https://github.com/owntone/owntone-server.git
synced 2024-12-28 08:05:56 -05:00
[web] Merge branch 'linting'
This commit is contained in:
commit
408057a45d
@ -25,21 +25,16 @@ export default [
|
|||||||
'max-statements': 'off',
|
'max-statements': 'off',
|
||||||
'no-bitwise': 'off',
|
'no-bitwise': 'off',
|
||||||
'no-magic-numbers': 'off',
|
'no-magic-numbers': 'off',
|
||||||
'no-negated-condition': 'off',
|
|
||||||
'no-nested-ternary': 'off',
|
'no-nested-ternary': 'off',
|
||||||
'no-plusplus': 'off',
|
'no-plusplus': 'off',
|
||||||
'no-shadow': 'off',
|
|
||||||
'no-ternary': 'off',
|
'no-ternary': 'off',
|
||||||
'no-undef': 'off',
|
'no-undef': 'off',
|
||||||
'no-unused-vars': ['error', { args: 'none', caughtErrors: 'none' }],
|
'no-unused-vars': ['error', { args: 'none', caughtErrors: 'none' }],
|
||||||
'no-useless-assignment': 'off',
|
|
||||||
'one-var': 'off',
|
'one-var': 'off',
|
||||||
'prefer-named-capture-group': 'off',
|
|
||||||
'sort-keys': 'off',
|
'sort-keys': 'off',
|
||||||
'vue/html-self-closing': 'off',
|
'vue/html-self-closing': 'off',
|
||||||
'vue/max-attributes-per-line': 'off',
|
'vue/max-attributes-per-line': 'off',
|
||||||
'vue/prop-name-casing': 'off',
|
'vue/prop-name-casing': 'off'
|
||||||
'vue/singleline-html-element-content-newline': 'off'
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -265,17 +265,6 @@ export default {
|
|||||||
document.querySelector('html').classList.remove('is-clipped')
|
document.querySelector('html').classList.remove('is-clipped')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
update_outputs() {
|
|
||||||
webapi.outputs().then(({ data }) => {
|
|
||||||
this.$store.commit(types.UPDATE_OUTPUTS, data.outputs)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
update_player_status() {
|
|
||||||
webapi.player_status().then(({ data }) => {
|
|
||||||
this.$store.commit(types.UPDATE_PLAYER_STATUS, data)
|
|
||||||
this.update_lyrics()
|
|
||||||
})
|
|
||||||
},
|
|
||||||
update_lastfm() {
|
update_lastfm() {
|
||||||
webapi.lastfm().then(({ data }) => {
|
webapi.lastfm().then(({ data }) => {
|
||||||
this.$store.commit(types.UPDATE_LASTFM, data)
|
this.$store.commit(types.UPDATE_LASTFM, data)
|
||||||
@ -299,12 +288,23 @@ export default {
|
|||||||
this.$store.commit(types.UPDATE_LYRICS)
|
this.$store.commit(types.UPDATE_LYRICS)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
update_outputs() {
|
||||||
|
webapi.outputs().then(({ data }) => {
|
||||||
|
this.$store.commit(types.UPDATE_OUTPUTS, data.outputs)
|
||||||
|
})
|
||||||
|
},
|
||||||
update_pairing() {
|
update_pairing() {
|
||||||
webapi.pairing().then(({ data }) => {
|
webapi.pairing().then(({ data }) => {
|
||||||
this.$store.commit(types.UPDATE_PAIRING, data)
|
this.$store.commit(types.UPDATE_PAIRING, data)
|
||||||
this.pairing_active = data.active
|
this.pairing_active = data.active
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
update_player_status() {
|
||||||
|
webapi.player_status().then(({ data }) => {
|
||||||
|
this.$store.commit(types.UPDATE_PLAYER_STATUS, data)
|
||||||
|
this.update_lyrics()
|
||||||
|
})
|
||||||
|
},
|
||||||
update_queue() {
|
update_queue() {
|
||||||
webapi.queue().then(({ data }) => {
|
webapi.queue().then(({ data }) => {
|
||||||
this.$store.commit(types.UPDATE_QUEUE, data)
|
this.$store.commit(types.UPDATE_QUEUE, data)
|
||||||
|
@ -94,7 +94,7 @@ export default {
|
|||||||
return this.media_kind || this.selected_item.media_kind
|
return this.media_kind || this.selected_item.media_kind
|
||||||
},
|
},
|
||||||
show_artwork() {
|
show_artwork() {
|
||||||
return this.$store.getters.settings_option(
|
return this.$store.getters.setting(
|
||||||
'webinterface',
|
'webinterface',
|
||||||
'show_cover_artwork_in_album_lists'
|
'show_cover_artwork_in_album_lists'
|
||||||
).value
|
).value
|
||||||
@ -122,10 +122,10 @@ export default {
|
|||||||
open_remove_podcast_dialog() {
|
open_remove_podcast_dialog() {
|
||||||
webapi
|
webapi
|
||||||
.library_album_tracks(this.selected_item.id, { limit: 1 })
|
.library_album_tracks(this.selected_item.id, { limit: 1 })
|
||||||
.then(({ data }) => {
|
.then(({ data: album }) => {
|
||||||
webapi.library_track_playlists(data.items[0].id).then(({ data }) => {
|
webapi.library_track_playlists(album.items[0].id).then(({ data }) => {
|
||||||
;[this.rss_playlist_to_remove] = data.items.filter(
|
;[this.rss_playlist_to_remove] = data.items.filter(
|
||||||
(pl) => pl.type === 'rss'
|
(playlist) => playlist.type === 'rss'
|
||||||
)
|
)
|
||||||
this.show_remove_podcast_modal = true
|
this.show_remove_podcast_modal = true
|
||||||
this.show_details_modal = false
|
this.show_details_modal = false
|
||||||
|
@ -53,7 +53,7 @@ export default {
|
|||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
show_artwork() {
|
show_artwork() {
|
||||||
return this.$store.getters.settings_option(
|
return this.$store.getters.setting(
|
||||||
'webinterface',
|
'webinterface',
|
||||||
'show_cover_artwork_in_album_lists'
|
'show_cover_artwork_in_album_lists'
|
||||||
).value
|
).value
|
||||||
|
@ -55,31 +55,28 @@ export default {
|
|||||||
const parsed = []
|
const parsed = []
|
||||||
if (raw) {
|
if (raw) {
|
||||||
// Parse the lyrics
|
// Parse the lyrics
|
||||||
const regex = /(\[(\d+):(\d+)(?:\.\d+)?\] ?)?(.*)/u
|
const regex =
|
||||||
raw.split('\n').forEach((item, index) => {
|
/\[(?<minutes>\d+):(?<seconds>\d+)(?:\.(?<hundredths>\d+))?\] ?(?<text>.*)/u
|
||||||
const matches = regex.exec(item)
|
raw.split('\n').forEach((line) => {
|
||||||
if (matches && matches[4]) {
|
const { text, minutes, seconds, hundredths } = regex.exec(line).groups
|
||||||
|
if (text) {
|
||||||
const verse = {
|
const verse = {
|
||||||
text: matches[4],
|
text,
|
||||||
time: matches[2] * 60 + Number(matches[3])
|
time:
|
||||||
|
minutes * 60 + Number(seconds) + Number(`.${hundredths || 0}`)
|
||||||
}
|
}
|
||||||
parsed.push(verse)
|
parsed.push(verse)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
// Split the verses into words
|
// Split the verses into words
|
||||||
parsed.forEach((verse, index, lyrics) => {
|
parsed.forEach((verse, index, lyrics) => {
|
||||||
const duration =
|
const unitDuration =
|
||||||
index < lyrics.length - 1 ? lyrics[index + 1].time - verse.time : 3
|
(lyrics[index + 1].time - verse.time || 3) / verse.text.length
|
||||||
const unitDuration = duration / verse.text.length
|
|
||||||
let delay = 0
|
let delay = 0
|
||||||
verse.words = verse.text.match(/\S+\s*/gu).map((text) => {
|
verse.words = verse.text.match(/\S+\s*/gu).map((text) => {
|
||||||
const duration = text.length * unitDuration
|
const duration = text.length * unitDuration
|
||||||
delay += duration
|
delay += duration
|
||||||
return {
|
return { duration, delay, text }
|
||||||
duration,
|
|
||||||
delay,
|
|
||||||
text
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -117,25 +114,25 @@ export default {
|
|||||||
}
|
}
|
||||||
// Not found, then start a binary search
|
// Not found, then start a binary search
|
||||||
let end = la.length - 1,
|
let end = la.length - 1,
|
||||||
index = 0,
|
index = -1,
|
||||||
start = 0
|
start = 0
|
||||||
while (start <= end) {
|
while (start <= end) {
|
||||||
index = (start + end) >> 1
|
index = (start + end) >> 1
|
||||||
const currentVerse = la[index]
|
const currentVerseTime = la[index].time
|
||||||
const nextVerse = la[index + 1]
|
const nextVerseTime = la[index + 1]?.time
|
||||||
if (
|
if (
|
||||||
currentVerse.time <= currentTime &&
|
currentVerseTime <= currentTime &&
|
||||||
(nextVerse?.time > currentTime || !nextVerse)
|
(nextVerseTime > currentTime || !nextVerseTime)
|
||||||
) {
|
) {
|
||||||
return index
|
break
|
||||||
}
|
}
|
||||||
if (currentVerse.time < currentTime) {
|
if (currentVerseTime < currentTime) {
|
||||||
start = index + 1
|
start = index + 1
|
||||||
} else {
|
} else {
|
||||||
end = index - 1
|
end = index - 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return -1
|
return index
|
||||||
}
|
}
|
||||||
this.reset_scrolling()
|
this.reset_scrolling()
|
||||||
return -1
|
return -1
|
||||||
@ -175,13 +172,11 @@ export default {
|
|||||||
pane.scrollTop
|
pane.scrollTop
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
start_scrolling(e) {
|
start_scrolling(event) {
|
||||||
// Consider only user events
|
// Consider only user events
|
||||||
if (e.screenX || e.screenX !== 0 || e.screenY || e.screenY !== 0) {
|
if (event.screenX ?? event.screenY) {
|
||||||
this.autoScrolling = false
|
this.autoScrolling = false
|
||||||
if (this.scrollingTimer) {
|
|
||||||
clearTimeout(this.scrollingTimer)
|
clearTimeout(this.scrollingTimer)
|
||||||
}
|
|
||||||
// Reenable automatic scrolling after 2 seconds
|
// Reenable automatic scrolling after 2 seconds
|
||||||
this.scrollingTimer = setTimeout((this.autoScrolling = true), 2000)
|
this.scrollingTimer = setTimeout((this.autoScrolling = true), 2000)
|
||||||
}
|
}
|
||||||
|
@ -74,8 +74,8 @@ export default {
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
disabled: true,
|
disabled: true,
|
||||||
playlist_name: '',
|
loading: false,
|
||||||
loading: false
|
playlist_name: ''
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -103,7 +103,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="navbar-brand is-flex-grow-1">
|
<div class="navbar-brand is-flex-grow-1">
|
||||||
<navbar-item-link :to="{ name: 'queue' }" exact class="mr-auto">
|
<navbar-item-link :to="{ name: 'queue' }" class="mr-auto">
|
||||||
<mdicon class="icon" name="playlist-play" size="24" />
|
<mdicon class="icon" name="playlist-play" size="24" />
|
||||||
</navbar-item-link>
|
</navbar-item-link>
|
||||||
<navbar-item-link
|
<navbar-item-link
|
||||||
|
@ -1,10 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<a
|
<a class="navbar-item" :href="href" @click.stop.prevent="open">
|
||||||
class="navbar-item"
|
|
||||||
:class="{ 'is-active': is_active }"
|
|
||||||
:href="full_path()"
|
|
||||||
@click.stop.prevent="open_link()"
|
|
||||||
>
|
|
||||||
<slot />
|
<slot />
|
||||||
</a>
|
</a>
|
||||||
</template>
|
</template>
|
||||||
@ -15,47 +10,21 @@ import * as types from '@/store/mutation_types'
|
|||||||
export default {
|
export default {
|
||||||
name: 'NavbarItemLink',
|
name: 'NavbarItemLink',
|
||||||
props: {
|
props: {
|
||||||
exact: Boolean,
|
|
||||||
to: { required: true, type: Object }
|
to: { required: true, type: Object }
|
||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
is_active() {
|
href() {
|
||||||
if (this.exact) {
|
return this.$router.resolve(this.to).href
|
||||||
return this.$route.path === this.to
|
|
||||||
}
|
|
||||||
return this.$route.path.startsWith(this.to)
|
|
||||||
},
|
|
||||||
|
|
||||||
show_burger_menu: {
|
|
||||||
get() {
|
|
||||||
return this.$store.state.show_burger_menu
|
|
||||||
},
|
|
||||||
set(value) {
|
|
||||||
this.$store.commit(types.SHOW_BURGER_MENU, value)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
show_player_menu: {
|
|
||||||
get() {
|
|
||||||
return this.$store.state.show_player_menu
|
|
||||||
},
|
|
||||||
set(value) {
|
|
||||||
this.$store.commit(types.SHOW_PLAYER_MENU, value)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
full_path() {
|
open() {
|
||||||
const resolved = this.$router.resolve(this.to)
|
if (this.$store.state.show_burger_menu) {
|
||||||
return resolved.href
|
|
||||||
},
|
|
||||||
open_link() {
|
|
||||||
if (this.show_burger_menu) {
|
|
||||||
this.$store.commit(types.SHOW_BURGER_MENU, false)
|
this.$store.commit(types.SHOW_BURGER_MENU, false)
|
||||||
}
|
}
|
||||||
if (this.show_player_menu) {
|
if (this.$store.state.show_player_menu) {
|
||||||
this.$store.commit(types.SHOW_PLAYER_MENU, false)
|
this.$store.commit(types.SHOW_PLAYER_MENU, false)
|
||||||
}
|
}
|
||||||
this.$router.push(this.to)
|
this.$router.push(this.to)
|
||||||
|
@ -54,7 +54,7 @@
|
|||||||
<mdicon class="icon" name="music-box-multiple" size="16" />
|
<mdicon class="icon" name="music-box-multiple" size="16" />
|
||||||
<b v-text="$t('navigation.playlists')" />
|
<b v-text="$t('navigation.playlists')" />
|
||||||
</navbar-item-link>
|
</navbar-item-link>
|
||||||
<navbar-item-link :to="{ name: 'music' }" exact>
|
<navbar-item-link :to="{ name: 'music' }">
|
||||||
<mdicon class="icon" name="music" size="16" />
|
<mdicon class="icon" name="music" size="16" />
|
||||||
<b v-text="$t('navigation.music')" />
|
<b v-text="$t('navigation.music')" />
|
||||||
</navbar-item-link>
|
</navbar-item-link>
|
||||||
@ -138,7 +138,7 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
show_audiobooks() {
|
show_audiobooks() {
|
||||||
return this.$store.getters.settings_option(
|
return this.$store.getters.setting(
|
||||||
'webinterface',
|
'webinterface',
|
||||||
'show_menu_item_audiobooks'
|
'show_menu_item_audiobooks'
|
||||||
).value
|
).value
|
||||||
@ -152,40 +152,34 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
show_files() {
|
show_files() {
|
||||||
return this.$store.getters.settings_option(
|
return this.$store.getters.setting('webinterface', 'show_menu_item_files')
|
||||||
'webinterface',
|
.value
|
||||||
'show_menu_item_files'
|
|
||||||
).value
|
|
||||||
},
|
},
|
||||||
show_music() {
|
show_music() {
|
||||||
return this.$store.getters.settings_option(
|
return this.$store.getters.setting('webinterface', 'show_menu_item_music')
|
||||||
'webinterface',
|
.value
|
||||||
'show_menu_item_music'
|
|
||||||
).value
|
|
||||||
},
|
},
|
||||||
show_player_menu() {
|
show_player_menu() {
|
||||||
return this.$store.state.show_player_menu
|
return this.$store.state.show_player_menu
|
||||||
},
|
},
|
||||||
show_playlists() {
|
show_playlists() {
|
||||||
return this.$store.getters.settings_option(
|
return this.$store.getters.setting(
|
||||||
'webinterface',
|
'webinterface',
|
||||||
'show_menu_item_playlists'
|
'show_menu_item_playlists'
|
||||||
).value
|
).value
|
||||||
},
|
},
|
||||||
show_podcasts() {
|
show_podcasts() {
|
||||||
return this.$store.getters.settings_option(
|
return this.$store.getters.setting(
|
||||||
'webinterface',
|
'webinterface',
|
||||||
'show_menu_item_podcasts'
|
'show_menu_item_podcasts'
|
||||||
).value
|
).value
|
||||||
},
|
},
|
||||||
show_radio() {
|
show_radio() {
|
||||||
return this.$store.getters.settings_option(
|
return this.$store.getters.setting('webinterface', 'show_menu_item_radio')
|
||||||
'webinterface',
|
.value
|
||||||
'show_menu_item_radio'
|
|
||||||
).value
|
|
||||||
},
|
},
|
||||||
show_search() {
|
show_search() {
|
||||||
return this.$store.getters.settings_option(
|
return this.$store.getters.setting(
|
||||||
'webinterface',
|
'webinterface',
|
||||||
'show_menu_item_search'
|
'show_menu_item_search'
|
||||||
).value
|
).value
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<input
|
<input
|
||||||
:id="option.name"
|
:id="setting.name"
|
||||||
v-model="option.value"
|
v-model="setting.value"
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
class="switch is-rounded mr-2"
|
class="switch is-rounded mr-2"
|
||||||
@change="update_setting"
|
@change="update_setting"
|
||||||
/>
|
/>
|
||||||
<label class="pt-0" :for="option.name">
|
<label class="pt-0" :for="setting.name">
|
||||||
<slot name="label" />
|
<slot name="label" />
|
||||||
</label>
|
</label>
|
||||||
<i
|
<i
|
||||||
@ -27,8 +27,8 @@ import webapi from '@/webapi'
|
|||||||
export default {
|
export default {
|
||||||
name: 'SettingsCheckbox',
|
name: 'SettingsCheckbox',
|
||||||
props: {
|
props: {
|
||||||
category_name: { required: true, type: String },
|
category: { required: true, type: String },
|
||||||
option_name: { required: true, type: String }
|
name: { required: true, type: String }
|
||||||
},
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
@ -54,40 +54,37 @@ export default {
|
|||||||
is_success() {
|
is_success() {
|
||||||
return this.statusUpdate === 'success'
|
return this.statusUpdate === 'success'
|
||||||
},
|
},
|
||||||
option() {
|
setting() {
|
||||||
const option = this.$store.getters.settings_option(
|
const setting = this.$store.getters.setting(this.category, this.name)
|
||||||
this.category_name,
|
if (!setting) {
|
||||||
this.option_name
|
|
||||||
)
|
|
||||||
if (!option) {
|
|
||||||
return {
|
return {
|
||||||
category: this.category_name,
|
category: this.category,
|
||||||
name: this.option_name,
|
name: this.name,
|
||||||
value: false
|
value: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return option
|
return setting
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
clear_status() {
|
clear_status() {
|
||||||
if (this.is_error) {
|
if (this.is_error) {
|
||||||
this.option.value = !this.option.value
|
this.setting.value = !this.setting.value
|
||||||
}
|
}
|
||||||
this.statusUpdate = ''
|
this.statusUpdate = ''
|
||||||
},
|
},
|
||||||
update_setting() {
|
update_setting() {
|
||||||
this.timerId = -1
|
this.timerId = -1
|
||||||
const option = {
|
const setting = {
|
||||||
category: this.category_name,
|
category: this.category,
|
||||||
name: this.option_name,
|
name: this.name,
|
||||||
value: this.option.value
|
value: this.setting.value
|
||||||
}
|
}
|
||||||
webapi
|
webapi
|
||||||
.settings_update(this.category_name, option)
|
.settings_update(this.category, setting)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.$store.dispatch('update_settings_option', option)
|
this.$store.dispatch('update_setting', setting)
|
||||||
this.statusUpdate = 'success'
|
this.statusUpdate = 'success'
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
inputmode="numeric"
|
inputmode="numeric"
|
||||||
min="0"
|
min="0"
|
||||||
:placeholder="placeholder"
|
:placeholder="placeholder"
|
||||||
:value="value"
|
:value="setting.value"
|
||||||
@input="set_update_timer"
|
@input="set_update_timer"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -33,9 +33,9 @@ import webapi from '@/webapi'
|
|||||||
export default {
|
export default {
|
||||||
name: 'SettingsIntfield',
|
name: 'SettingsIntfield',
|
||||||
props: {
|
props: {
|
||||||
category_name: { required: true, type: String },
|
category: { required: true, type: String },
|
||||||
disabled: Boolean,
|
disabled: Boolean,
|
||||||
option_name: { required: true, type: String },
|
name: { required: true, type: String },
|
||||||
placeholder: { default: '', type: String }
|
placeholder: { default: '', type: String }
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -48,11 +48,6 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
category() {
|
|
||||||
return this.$store.state.settings.categories.find(
|
|
||||||
(elem) => elem.name === this.category_name
|
|
||||||
)
|
|
||||||
},
|
|
||||||
info() {
|
info() {
|
||||||
if (this.statusUpdate === 'success') {
|
if (this.statusUpdate === 'success') {
|
||||||
return this.$t('setting.saved')
|
return this.$t('setting.saved')
|
||||||
@ -67,16 +62,8 @@ export default {
|
|||||||
is_success() {
|
is_success() {
|
||||||
return this.statusUpdate === 'success'
|
return this.statusUpdate === 'success'
|
||||||
},
|
},
|
||||||
option() {
|
setting() {
|
||||||
if (!this.category) {
|
return this.$store.getters.setting(this.category, this.name)
|
||||||
return {}
|
|
||||||
}
|
|
||||||
return this.category.options.find(
|
|
||||||
(elem) => elem.name === this.option_name
|
|
||||||
)
|
|
||||||
},
|
|
||||||
value() {
|
|
||||||
return this.option.value
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -100,15 +87,15 @@ export default {
|
|||||||
this.statusUpdate = ''
|
this.statusUpdate = ''
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const option = {
|
const setting = {
|
||||||
category: this.category.name,
|
category: this.category,
|
||||||
name: this.option_name,
|
name: this.name,
|
||||||
value: newValue
|
value: newValue
|
||||||
}
|
}
|
||||||
webapi
|
webapi
|
||||||
.settings_update(this.category.name, option)
|
.settings_update(this.category, setting)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.$store.dispatch('update_settings_option', option)
|
this.$store.dispatch('update_setting', setting)
|
||||||
this.statusUpdate = 'success'
|
this.statusUpdate = 'success'
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
class="input"
|
class="input"
|
||||||
type="text"
|
type="text"
|
||||||
:placeholder="placeholder"
|
:placeholder="placeholder"
|
||||||
:value="value"
|
:value="setting.value"
|
||||||
@input="set_update_timer"
|
@input="set_update_timer"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -32,9 +32,9 @@ import webapi from '@/webapi'
|
|||||||
export default {
|
export default {
|
||||||
name: 'SettingsTextfield',
|
name: 'SettingsTextfield',
|
||||||
props: {
|
props: {
|
||||||
category_name: { required: true, type: String },
|
category: { required: true, type: String },
|
||||||
disabled: Boolean,
|
disabled: Boolean,
|
||||||
option_name: { required: true, type: String },
|
name: { required: true, type: String },
|
||||||
placeholder: { default: '', type: String }
|
placeholder: { default: '', type: String }
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -47,11 +47,6 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
category() {
|
|
||||||
return this.$store.state.settings.categories.find(
|
|
||||||
(elem) => elem.name === this.category_name
|
|
||||||
)
|
|
||||||
},
|
|
||||||
info() {
|
info() {
|
||||||
if (this.statusUpdate === 'success') {
|
if (this.statusUpdate === 'success') {
|
||||||
return this.$t('setting.saved')
|
return this.$t('setting.saved')
|
||||||
@ -66,16 +61,8 @@ export default {
|
|||||||
is_success() {
|
is_success() {
|
||||||
return this.statusUpdate === 'success'
|
return this.statusUpdate === 'success'
|
||||||
},
|
},
|
||||||
option() {
|
setting() {
|
||||||
if (!this.category) {
|
return this.$store.getters.setting(this.category, this.name)
|
||||||
return {}
|
|
||||||
}
|
|
||||||
return this.category.options.find(
|
|
||||||
(elem) => elem.name === this.option_name
|
|
||||||
)
|
|
||||||
},
|
|
||||||
value() {
|
|
||||||
return this.option.value
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -101,15 +88,15 @@ export default {
|
|||||||
this.statusUpdate = ''
|
this.statusUpdate = ''
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const option = {
|
const setting = {
|
||||||
category: this.category.name,
|
category: this.category,
|
||||||
name: this.option_name,
|
name: this.name,
|
||||||
value: newValue
|
value: newValue
|
||||||
}
|
}
|
||||||
webapi
|
webapi
|
||||||
.settings_update(this.category.name, option)
|
.settings_update(this.category, setting)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.$store.dispatch('update_settings_option', option)
|
this.$store.dispatch('update_setting', setting)
|
||||||
this.statusUpdate = 'success'
|
this.statusUpdate = 'success'
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
|
@ -31,8 +31,8 @@ export const filters = {
|
|||||||
.setLocale(locale.value)
|
.setLocale(locale.value)
|
||||||
.toLocaleString(DateTime.DATETIME_MED)
|
.toLocaleString(DateTime.DATETIME_MED)
|
||||||
},
|
},
|
||||||
durationInDays(value_ms) {
|
durationInDays(value) {
|
||||||
const minutes = Math.floor(value_ms / 60000)
|
const minutes = Math.floor(value / 60000)
|
||||||
if (minutes > 1440) {
|
if (minutes > 1440) {
|
||||||
return Duration.fromObject({ minutes })
|
return Duration.fromObject({ minutes })
|
||||||
.shiftTo('days', 'hours', 'minutes')
|
.shiftTo('days', 'hours', 'minutes')
|
||||||
@ -44,9 +44,9 @@ export const filters = {
|
|||||||
}
|
}
|
||||||
return Duration.fromObject({ minutes }).shiftTo('minutes').toHuman()
|
return Duration.fromObject({ minutes }).shiftTo('minutes').toHuman()
|
||||||
},
|
},
|
||||||
durationInHours(value_ms) {
|
durationInHours(value) {
|
||||||
const format = value_ms >= 3600000 ? 'h:mm:ss' : 'm:ss'
|
const format = value >= 3600000 ? 'h:mm:ss' : 'm:ss'
|
||||||
return Duration.fromMillis(value_ms).toFormat(format)
|
return Duration.fromMillis(value).toFormat(format)
|
||||||
},
|
},
|
||||||
number(value) {
|
number(value) {
|
||||||
return value.toLocaleString(locale.value)
|
return value.toLocaleString(locale.value)
|
||||||
|
@ -29,10 +29,10 @@ export default {
|
|||||||
this.context = new (window.AudioContext || window.webkitAudioContext)()
|
this.context = new (window.AudioContext || window.webkitAudioContext)()
|
||||||
const source = this.context.createMediaElementSource(this.audio)
|
const source = this.context.createMediaElementSource(this.audio)
|
||||||
source.connect(this.context.destination)
|
source.connect(this.context.destination)
|
||||||
this.audio.addEventListener('canplaythrough', (e) => {
|
this.audio.addEventListener('canplaythrough', () => {
|
||||||
this.audio.play()
|
this.audio.play()
|
||||||
})
|
})
|
||||||
this.audio.addEventListener('canplay', (e) => {
|
this.audio.addEventListener('canplay', () => {
|
||||||
this.audio.play()
|
this.audio.play()
|
||||||
})
|
})
|
||||||
return this.audio
|
return this.audio
|
||||||
@ -42,17 +42,17 @@ export default {
|
|||||||
stop() {
|
stop() {
|
||||||
try {
|
try {
|
||||||
this.audio.pause()
|
this.audio.pause()
|
||||||
} catch (e) {
|
} catch (error) {
|
||||||
// Continue regardless of error
|
// Continue regardless of error
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
this.audio.stop()
|
this.audio.stop()
|
||||||
} catch (e) {
|
} catch (error) {
|
||||||
// Continue regardless of error
|
// Continue regardless of error
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
this.audio.close()
|
this.audio.close()
|
||||||
} catch (e) {
|
} catch (error) {
|
||||||
// Continue regardless of error
|
// Continue regardless of error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ const NO_INDEX = 'NO_INDEX'
|
|||||||
const numberComparator = (a, b) => a - b
|
const numberComparator = (a, b) => a - b
|
||||||
const stringComparator = (a, b) => a.localeCompare(b, locale.value)
|
const stringComparator = (a, b) => a.localeCompare(b, locale.value)
|
||||||
const dateComparator = (a, b) =>
|
const dateComparator = (a, b) =>
|
||||||
new Date(a) - new Date(b) || (!a ? -1 : !b ? 1 : 0)
|
new Date(a) - new Date(b) || (a ? (b ? 0 : 1) : -1)
|
||||||
|
|
||||||
const createComparators = (criteria) =>
|
const createComparators = (criteria) =>
|
||||||
criteria.map(({ field, type, order = 1 }) => {
|
criteria.map(({ field, type, order = 1 }) => {
|
||||||
@ -18,7 +18,7 @@ const createComparators = (criteria) =>
|
|||||||
case Date:
|
case Date:
|
||||||
return (a, b) => dateComparator(a[field], b[field]) * order
|
return (a, b) => dateComparator(a[field], b[field]) * order
|
||||||
default:
|
default:
|
||||||
return (a, b) => 0
|
return () => 0
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -61,7 +61,7 @@ const createIndexer = ({ field, type } = {}) => {
|
|||||||
case 'Digits':
|
case 'Digits':
|
||||||
return (item) => numberIndex(item[field])
|
return (item) => numberIndex(item[field])
|
||||||
default:
|
default:
|
||||||
return (item) => NO_INDEX
|
return () => NO_INDEX
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,7 +80,6 @@ export class GroupedList {
|
|||||||
}
|
}
|
||||||
|
|
||||||
group({ criteria = [], filters = [], index } = {}) {
|
group({ criteria = [], filters = [], index } = {}) {
|
||||||
const indexer = createIndexer(index)
|
|
||||||
const itemsFiltered = this.items.filter((item) =>
|
const itemsFiltered = this.items.filter((item) =>
|
||||||
filters.every((filter) => filter(item))
|
filters.every((filter) => filter(item))
|
||||||
)
|
)
|
||||||
@ -94,13 +93,15 @@ export class GroupedList {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
// Group item list
|
// Group item list
|
||||||
|
const indexer = createIndexer(index)
|
||||||
this.itemsGrouped = itemsSorted.reduce((map, item) => {
|
this.itemsGrouped = itemsSorted.reduce((map, item) => {
|
||||||
const index = indexer(item)
|
const key = indexer(item)
|
||||||
map.set(index, [...(map.get(index) || []), item])
|
map.set(key, [...(map.get(key) || []), item])
|
||||||
return map
|
return map
|
||||||
}, new Map())
|
}, new Map())
|
||||||
// Create index list
|
// Create index list
|
||||||
this.indices = Array.from(this.itemsGrouped.keys())
|
this.indices = Array.from(this.itemsGrouped.keys())
|
||||||
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
*generate() {
|
*generate() {
|
||||||
|
@ -158,7 +158,7 @@
|
|||||||
<a href="https://vuejs.org/">Vue.js</a>
|
<a href="https://vuejs.org/">Vue.js</a>
|
||||||
</template>
|
</template>
|
||||||
<template #axios>
|
<template #axios>
|
||||||
<a href="https://github.com/mzabriskie/axios">axios</a>
|
<a href="https://github.com/axios/axios">axios</a>
|
||||||
</template>
|
</template>
|
||||||
<template #others>
|
<template #others>
|
||||||
<a
|
<a
|
||||||
|
@ -41,8 +41,8 @@
|
|||||||
<div class="column">
|
<div class="column">
|
||||||
<p class="heading mb-5" v-text="$t('page.albums.sort.title')" />
|
<p class="heading mb-5" v-text="$t('page.albums.sort.title')" />
|
||||||
<control-dropdown
|
<control-dropdown
|
||||||
v-model:value="selected_grouping_option_id"
|
v-model:value="selected_grouping_id"
|
||||||
:options="grouping_options"
|
:options="groupings"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -101,7 +101,7 @@ export default {
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
albums_list: new GroupedList(),
|
albums_list: new GroupedList(),
|
||||||
grouping_options: [
|
groupings: [
|
||||||
{
|
{
|
||||||
id: 1,
|
id: 1,
|
||||||
name: this.$t('page.albums.sort.name'),
|
name: this.$t('page.albums.sort.name'),
|
||||||
@ -151,16 +151,14 @@ export default {
|
|||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
albums() {
|
albums() {
|
||||||
const grouping = this.grouping_options.find(
|
const { options } = this.groupings.find(
|
||||||
(o) => o.id === this.selected_grouping_option_id
|
(grouping) => grouping.id === this.selected_grouping_id
|
||||||
)
|
)
|
||||||
grouping.options.filters = [
|
options.filters = [
|
||||||
(album) => !this.hide_singles || album.track_count > 2,
|
(album) => !this.hide_singles || album.track_count > 2,
|
||||||
(album) => !this.hide_spotify || album.data_kind !== 'spotify'
|
(album) => !this.hide_spotify || album.data_kind !== 'spotify'
|
||||||
]
|
]
|
||||||
this.albums_list.group(grouping.options)
|
return this.albums_list.group(options)
|
||||||
|
|
||||||
return this.albums_list
|
|
||||||
},
|
},
|
||||||
hide_singles: {
|
hide_singles: {
|
||||||
get() {
|
get() {
|
||||||
@ -178,7 +176,7 @@ export default {
|
|||||||
this.$store.commit(types.HIDE_SPOTIFY, value)
|
this.$store.commit(types.HIDE_SPOTIFY, value)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
selected_grouping_option_id: {
|
selected_grouping_id: {
|
||||||
get() {
|
get() {
|
||||||
return this.$store.state.albums_sort
|
return this.$store.state.albums_sort
|
||||||
},
|
},
|
||||||
|
@ -24,8 +24,8 @@
|
|||||||
<div class="column">
|
<div class="column">
|
||||||
<p class="heading mb-5" v-text="$t('page.artist.sort.title')" />
|
<p class="heading mb-5" v-text="$t('page.artist.sort.title')" />
|
||||||
<control-dropdown
|
<control-dropdown
|
||||||
v-model:value="selected_grouping_option_id"
|
v-model:value="selected_grouping_id"
|
||||||
:options="grouping_options"
|
:options="groupings"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -112,7 +112,7 @@ export default {
|
|||||||
return {
|
return {
|
||||||
albums_list: new GroupedList(),
|
albums_list: new GroupedList(),
|
||||||
artist: {},
|
artist: {},
|
||||||
grouping_options: [
|
groupings: [
|
||||||
{
|
{
|
||||||
id: 1,
|
id: 1,
|
||||||
name: this.$t('page.artist.sort.name'),
|
name: this.$t('page.artist.sort.name'),
|
||||||
@ -130,14 +130,13 @@ export default {
|
|||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
albums() {
|
albums() {
|
||||||
const grouping = this.grouping_options.find(
|
const { options } = this.groupings.find(
|
||||||
(o) => o.id === this.selected_grouping_option_id
|
(grouping) => grouping.id === this.selected_grouping_id
|
||||||
)
|
)
|
||||||
grouping.options.filters = [
|
options.filters = [
|
||||||
(album) => !this.hide_spotify || album.data_kind !== 'spotify'
|
(album) => !this.hide_spotify || album.data_kind !== 'spotify'
|
||||||
]
|
]
|
||||||
this.albums_list.group(grouping.options)
|
return this.albums_list.group(options)
|
||||||
return this.albums_list
|
|
||||||
},
|
},
|
||||||
hide_spotify: {
|
hide_spotify: {
|
||||||
get() {
|
get() {
|
||||||
@ -147,7 +146,7 @@ export default {
|
|||||||
this.$store.commit(types.HIDE_SPOTIFY, value)
|
this.$store.commit(types.HIDE_SPOTIFY, value)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
selected_grouping_option_id: {
|
selected_grouping_id: {
|
||||||
get() {
|
get() {
|
||||||
return this.$store.state.artist_albums_sort
|
return this.$store.state.artist_albums_sort
|
||||||
},
|
},
|
||||||
|
@ -32,7 +32,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #no-more> </template>
|
<template #no-more>
|
||||||
|
<br />
|
||||||
|
</template>
|
||||||
</VueEternalLoading>
|
</VueEternalLoading>
|
||||||
<modal-dialog-artist-spotify
|
<modal-dialog-artist-spotify
|
||||||
:item="artist"
|
:item="artist"
|
||||||
|
@ -25,8 +25,8 @@
|
|||||||
<div class="column">
|
<div class="column">
|
||||||
<p class="heading mb-5" v-text="$t('page.artist.sort.title')" />
|
<p class="heading mb-5" v-text="$t('page.artist.sort.title')" />
|
||||||
<control-dropdown
|
<control-dropdown
|
||||||
v-model:value="selected_grouping_option_id"
|
v-model:value="selected_grouping_id"
|
||||||
:options="grouping_options"
|
:options="groupings"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -114,7 +114,7 @@ export default {
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
artist: {},
|
artist: {},
|
||||||
grouping_options: [
|
groupings: [
|
||||||
{
|
{
|
||||||
id: 1,
|
id: 1,
|
||||||
name: this.$t('page.artist.sort.name'),
|
name: this.$t('page.artist.sort.name'),
|
||||||
@ -150,7 +150,7 @@ export default {
|
|||||||
this.$store.commit(types.HIDE_SPOTIFY, value)
|
this.$store.commit(types.HIDE_SPOTIFY, value)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
selected_grouping_option_id: {
|
selected_grouping_id: {
|
||||||
get() {
|
get() {
|
||||||
return this.$store.state.artist_tracks_sort
|
return this.$store.state.artist_tracks_sort
|
||||||
},
|
},
|
||||||
@ -165,14 +165,13 @@ export default {
|
|||||||
return this.tracks_list.items.map((item) => item.uri).join()
|
return this.tracks_list.items.map((item) => item.uri).join()
|
||||||
},
|
},
|
||||||
tracks() {
|
tracks() {
|
||||||
const grouping = this.grouping_options.find(
|
const { options } = this.groupings.find(
|
||||||
(o) => o.id === this.selected_grouping_option_id
|
(grouping) => grouping.id === this.selected_grouping_id
|
||||||
)
|
)
|
||||||
grouping.options.filters = [
|
options.filters = [
|
||||||
(track) => !this.hide_spotify || track.data_kind !== 'spotify'
|
(track) => !this.hide_spotify || track.data_kind !== 'spotify'
|
||||||
]
|
]
|
||||||
this.tracks_list.group(grouping.options)
|
return this.tracks_list.group(options)
|
||||||
return this.tracks_list
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -41,8 +41,8 @@
|
|||||||
<div class="column">
|
<div class="column">
|
||||||
<p class="heading mb-5" v-text="$t('page.artists.sort.title')" />
|
<p class="heading mb-5" v-text="$t('page.artists.sort.title')" />
|
||||||
<control-dropdown
|
<control-dropdown
|
||||||
v-model:value="selected_grouping_option_id"
|
v-model:value="selected_grouping_id"
|
||||||
:options="grouping_options"
|
:options="groupings"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -101,7 +101,7 @@ export default {
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
artists_list: new GroupedList(),
|
artists_list: new GroupedList(),
|
||||||
grouping_options: [
|
groupings: [
|
||||||
{
|
{
|
||||||
id: 1,
|
id: 1,
|
||||||
name: this.$t('page.artists.sort.name'),
|
name: this.$t('page.artists.sort.name'),
|
||||||
@ -122,19 +122,15 @@ export default {
|
|||||||
computed: {
|
computed: {
|
||||||
// Wraps GroupedList and updates it if filter or sort changes
|
// Wraps GroupedList and updates it if filter or sort changes
|
||||||
artists() {
|
artists() {
|
||||||
if (!this.artists_list) {
|
const { options } = this.groupings.find(
|
||||||
return []
|
(grouping) => grouping.id === this.selected_grouping_id
|
||||||
}
|
|
||||||
const grouping = this.grouping_options.find(
|
|
||||||
(o) => o.id === this.selected_grouping_option_id
|
|
||||||
)
|
)
|
||||||
grouping.options.filters = [
|
options.filters = [
|
||||||
(artist) =>
|
(artist) =>
|
||||||
!this.hide_singles || artist.track_count > artist.album_count * 2,
|
!this.hide_singles || artist.track_count > artist.album_count * 2,
|
||||||
(artist) => !this.hide_spotify || artist.data_kind !== 'spotify'
|
(artist) => !this.hide_spotify || artist.data_kind !== 'spotify'
|
||||||
]
|
]
|
||||||
this.artists_list.group(grouping.options)
|
return this.artists_list.group(options)
|
||||||
return this.artists_list
|
|
||||||
},
|
},
|
||||||
hide_singles: {
|
hide_singles: {
|
||||||
get() {
|
get() {
|
||||||
@ -152,7 +148,7 @@ export default {
|
|||||||
this.$store.commit(types.HIDE_SPOTIFY, value)
|
this.$store.commit(types.HIDE_SPOTIFY, value)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
selected_grouping_option_id: {
|
selected_grouping_id: {
|
||||||
get() {
|
get() {
|
||||||
return this.$store.state.artists_sort
|
return this.$store.state.artists_sort
|
||||||
},
|
},
|
||||||
|
@ -7,8 +7,8 @@
|
|||||||
<div class="column">
|
<div class="column">
|
||||||
<p class="heading mb-5" v-text="$t('page.artist.sort.title')" />
|
<p class="heading mb-5" v-text="$t('page.artist.sort.title')" />
|
||||||
<control-dropdown
|
<control-dropdown
|
||||||
v-model:value="selected_grouping_option_id"
|
v-model:value="selected_grouping_id"
|
||||||
:options="grouping_options"
|
:options="groupings"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -102,7 +102,7 @@ export default {
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
composer: {},
|
composer: {},
|
||||||
grouping_options: [
|
groupings: [
|
||||||
{
|
{
|
||||||
id: 1,
|
id: 1,
|
||||||
name: this.$t('page.composer.sort.name'),
|
name: this.$t('page.composer.sort.name'),
|
||||||
@ -126,7 +126,7 @@ export default {
|
|||||||
expression() {
|
expression() {
|
||||||
return `composer is "${this.composer.name}" and media_kind is music`
|
return `composer is "${this.composer.name}" and media_kind is music`
|
||||||
},
|
},
|
||||||
selected_grouping_option_id: {
|
selected_grouping_id: {
|
||||||
get() {
|
get() {
|
||||||
return this.$store.state.composer_tracks_sort
|
return this.$store.state.composer_tracks_sort
|
||||||
},
|
},
|
||||||
@ -135,11 +135,10 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
tracks() {
|
tracks() {
|
||||||
const grouping = this.grouping_options.find(
|
const { options } = this.groupings.find(
|
||||||
(o) => o.id === this.selected_grouping_option_id
|
(grouping) => grouping.id === this.selected_grouping_id
|
||||||
)
|
)
|
||||||
this.tracks_list.group(grouping.options)
|
return this.tracks_list.group(options)
|
||||||
return this.tracks_list
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -125,7 +125,7 @@ export default {
|
|||||||
webapi.player_play_expression(this.play_expression, false)
|
webapi.player_play_expression(this.play_expression, false)
|
||||||
},
|
},
|
||||||
transform(path) {
|
transform(path) {
|
||||||
return { path, name: path.slice(path.lastIndexOf('/') + 1) }
|
return { name: path.slice(path.lastIndexOf('/') + 1), path }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,8 +7,8 @@
|
|||||||
<div class="column">
|
<div class="column">
|
||||||
<p class="heading mb-5" v-text="$t('page.genre.sort.title')" />
|
<p class="heading mb-5" v-text="$t('page.genre.sort.title')" />
|
||||||
<control-dropdown
|
<control-dropdown
|
||||||
v-model:value="selected_grouping_option_id"
|
v-model:value="selected_grouping_id"
|
||||||
:options="grouping_options"
|
:options="groupings"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -97,7 +97,7 @@ export default {
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
genre: {},
|
genre: {},
|
||||||
grouping_options: [
|
groupings: [
|
||||||
{
|
{
|
||||||
id: 1,
|
id: 1,
|
||||||
name: this.$t('page.genre.sort.name'),
|
name: this.$t('page.genre.sort.name'),
|
||||||
@ -122,7 +122,7 @@ export default {
|
|||||||
expression() {
|
expression() {
|
||||||
return `genre is "${this.genre.name}" and media_kind is ${this.media_kind}`
|
return `genre is "${this.genre.name}" and media_kind is ${this.media_kind}`
|
||||||
},
|
},
|
||||||
selected_grouping_option_id: {
|
selected_grouping_id: {
|
||||||
get() {
|
get() {
|
||||||
return this.$store.state.genre_tracks_sort
|
return this.$store.state.genre_tracks_sort
|
||||||
},
|
},
|
||||||
@ -131,11 +131,10 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
tracks() {
|
tracks() {
|
||||||
const grouping = this.grouping_options.find(
|
const { options } = this.groupings.find(
|
||||||
(o) => o.id === this.selected_grouping_option_id
|
(grouping) => grouping.id === this.selected_grouping_id
|
||||||
)
|
)
|
||||||
this.tracks_list.group(grouping.options)
|
return this.tracks_list.group(options)
|
||||||
return this.tracks_list
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="fd-page-with-tabs">
|
<div class="fd-page-with-tabs">
|
||||||
<tabs-music />
|
<tabs-music />
|
||||||
<!-- Recently added -->
|
|
||||||
<content-with-heading>
|
<content-with-heading>
|
||||||
<template #heading-left>
|
<template #heading-left>
|
||||||
<p class="title is-4" v-text="$t('page.music.recently-added.title')" />
|
<p class="title is-4" v-text="$t('page.music.recently-added.title')" />
|
||||||
</template>
|
</template>
|
||||||
<template #content>
|
<template #content>
|
||||||
<list-albums :items="recently_added" />
|
<list-albums :items="albums" />
|
||||||
</template>
|
</template>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<nav class="level">
|
<nav class="level">
|
||||||
@ -22,13 +21,12 @@
|
|||||||
</nav>
|
</nav>
|
||||||
</template>
|
</template>
|
||||||
</content-with-heading>
|
</content-with-heading>
|
||||||
<!-- Recently played -->
|
|
||||||
<content-with-heading>
|
<content-with-heading>
|
||||||
<template #heading-left>
|
<template #heading-left>
|
||||||
<p class="title is-4" v-text="$t('page.music.recently-played.title')" />
|
<p class="title is-4" v-text="$t('page.music.recently-played.title')" />
|
||||||
</template>
|
</template>
|
||||||
<template #content>
|
<template #content>
|
||||||
<list-tracks :items="recently_played" />
|
<list-tracks :items="tracks" />
|
||||||
</template>
|
</template>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<nav class="level">
|
<nav class="level">
|
||||||
@ -73,8 +71,8 @@ const dataObject = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
set(vm, response) {
|
set(vm, response) {
|
||||||
vm.recently_added = new GroupedList(response[0].data.albums)
|
vm.albums = new GroupedList(response[0].data.albums)
|
||||||
vm.recently_played = new GroupedList(response[1].data.tracks)
|
vm.tracks = new GroupedList(response[1].data.tracks)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,8 +88,8 @@ export default {
|
|||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
recently_added: [],
|
albums: [],
|
||||||
recently_played: { items: [] },
|
tracks: { items: [] },
|
||||||
selected_track: {}
|
selected_track: {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<p class="title is-4" v-text="$t('page.music.recently-added.title')" />
|
<p class="title is-4" v-text="$t('page.music.recently-added.title')" />
|
||||||
</template>
|
</template>
|
||||||
<template #content>
|
<template #content>
|
||||||
<list-albums :items="recently_added" />
|
<list-albums :items="albums" />
|
||||||
</template>
|
</template>
|
||||||
</content-with-heading>
|
</content-with-heading>
|
||||||
</div>
|
</div>
|
||||||
@ -22,7 +22,7 @@ import webapi from '@/webapi'
|
|||||||
|
|
||||||
const dataObject = {
|
const dataObject = {
|
||||||
load(to) {
|
load(to) {
|
||||||
const limit = store.getters.settings_option_recently_added_limit
|
const limit = store.getters.setting_recently_added_limit
|
||||||
return webapi.search({
|
return webapi.search({
|
||||||
expression:
|
expression:
|
||||||
'media_kind is music having track_count > 3 order by time_added desc',
|
'media_kind is music having track_count > 3 order by time_added desc',
|
||||||
@ -32,7 +32,7 @@ const dataObject = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
set(vm, response) {
|
set(vm, response) {
|
||||||
vm.recently_added = new GroupedList(response.data.albums, {
|
vm.albums = new GroupedList(response.data.albums, {
|
||||||
criteria: [{ field: 'time_added', order: -1, type: Date }],
|
criteria: [{ field: 'time_added', order: -1, type: Date }],
|
||||||
index: { field: 'time_added', type: Date }
|
index: { field: 'time_added', type: Date }
|
||||||
})
|
})
|
||||||
@ -51,7 +51,7 @@ export default {
|
|||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
recently_added: new GroupedList()
|
albums: new GroupedList()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<p class="title is-4" v-text="$t('page.music.recently-played.title')" />
|
<p class="title is-4" v-text="$t('page.music.recently-played.title')" />
|
||||||
</template>
|
</template>
|
||||||
<template #content>
|
<template #content>
|
||||||
<list-tracks :items="recently_played" />
|
<list-tracks :items="tracks" />
|
||||||
</template>
|
</template>
|
||||||
</content-with-heading>
|
</content-with-heading>
|
||||||
</div>
|
</div>
|
||||||
@ -30,7 +30,7 @@ const dataObject = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
set(vm, response) {
|
set(vm, response) {
|
||||||
vm.recently_played = new GroupedList(response.data.tracks)
|
vm.tracks = new GroupedList(response.data.tracks)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,7 +46,7 @@ export default {
|
|||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
recently_played: {}
|
tracks: {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="fd-page-with-tabs">
|
<div class="fd-page-with-tabs">
|
||||||
<tabs-music />
|
<tabs-music />
|
||||||
<!-- New Releases -->
|
|
||||||
<content-with-heading>
|
<content-with-heading>
|
||||||
<template #heading-left>
|
<template #heading-left>
|
||||||
<p class="title is-4" v-text="$t('page.spotify.music.new-releases')" />
|
<p class="title is-4" v-text="$t('page.spotify.music.new-releases')" />
|
||||||
</template>
|
</template>
|
||||||
<template #content>
|
<template #content>
|
||||||
<list-albums-spotify :items="new_releases" />
|
<list-albums-spotify :items="albums" />
|
||||||
</template>
|
</template>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<nav class="level">
|
<nav class="level">
|
||||||
@ -22,7 +21,6 @@
|
|||||||
</nav>
|
</nav>
|
||||||
</template>
|
</template>
|
||||||
</content-with-heading>
|
</content-with-heading>
|
||||||
<!-- Featured Playlists -->
|
|
||||||
<content-with-heading>
|
<content-with-heading>
|
||||||
<template #heading-left>
|
<template #heading-left>
|
||||||
<p
|
<p
|
||||||
@ -31,7 +29,7 @@
|
|||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<template #content>
|
<template #content>
|
||||||
<list-playlists-spotify :items="featured_playlists" />
|
<list-playlists-spotify :items="playlists" />
|
||||||
</template>
|
</template>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<nav class="level">
|
<nav class="level">
|
||||||
@ -76,8 +74,8 @@ const dataObject = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
set(vm, response) {
|
set(vm, response) {
|
||||||
vm.new_releases = response[0].albums.items
|
vm.albums = response[0].albums.items
|
||||||
vm.featured_playlists = response[1].playlists.items
|
vm.playlists = response[1].playlists.items
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,8 +96,8 @@ export default {
|
|||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
featured_playlists: [],
|
playlists: [],
|
||||||
new_releases: []
|
albums: []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<template #content>
|
<template #content>
|
||||||
<list-playlists-spotify :items="featured_playlists" />
|
<list-playlists-spotify :items="playlists" />
|
||||||
</template>
|
</template>
|
||||||
</content-with-heading>
|
</content-with-heading>
|
||||||
</div>
|
</div>
|
||||||
@ -35,7 +35,7 @@ const dataObject = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
set(vm, response) {
|
set(vm, response) {
|
||||||
vm.featured_playlists = response.playlists.items
|
vm.playlists = response.playlists.items
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,7 +55,7 @@ export default {
|
|||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
featured_playlists: []
|
playlists: []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<p class="title is-4" v-text="$t('page.spotify.music.new-releases')" />
|
<p class="title is-4" v-text="$t('page.spotify.music.new-releases')" />
|
||||||
</template>
|
</template>
|
||||||
<template #content>
|
<template #content>
|
||||||
<list-albums-spotify :items="new_releases" />
|
<list-albums-spotify :items="albums" />
|
||||||
</template>
|
</template>
|
||||||
</content-with-heading>
|
</content-with-heading>
|
||||||
</div>
|
</div>
|
||||||
@ -32,7 +32,7 @@ const dataObject = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
set(vm, response) {
|
set(vm, response) {
|
||||||
vm.new_releases = response.albums.items
|
vm.albums = response.albums.items
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,7 +52,7 @@ export default {
|
|||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
new_releases: []
|
albums: []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -76,8 +76,8 @@ export default {
|
|||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
cursor: mdiCancel,
|
|
||||||
INTERVAL,
|
INTERVAL,
|
||||||
|
cursor: mdiCancel,
|
||||||
interval_id: 0,
|
interval_id: 0,
|
||||||
is_dragged: false,
|
is_dragged: false,
|
||||||
selected_item: {},
|
selected_item: {},
|
||||||
@ -87,11 +87,11 @@ export default {
|
|||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
composer() {
|
composer() {
|
||||||
if (this.settings_option_show_composer_now_playing) {
|
if (this.setting_show_composer_now_playing) {
|
||||||
if (
|
if (
|
||||||
!this.settings_option_show_composer_for_genre ||
|
!this.setting_show_composer_for_genre ||
|
||||||
(this.track.genre &&
|
(this.track.genre &&
|
||||||
this.settings_option_show_composer_for_genre
|
this.setting_show_composer_for_genre
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
.split(',')
|
.split(',')
|
||||||
.findIndex(
|
.findIndex(
|
||||||
@ -105,7 +105,7 @@ export default {
|
|||||||
return null
|
return null
|
||||||
},
|
},
|
||||||
filepath() {
|
filepath() {
|
||||||
if (this.settings_option_show_filepath_now_playing) {
|
if (this.setting_show_filepath_now_playing) {
|
||||||
return this.track.path
|
return this.track.path
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
@ -119,14 +119,14 @@ export default {
|
|||||||
player() {
|
player() {
|
||||||
return this.$store.state.player
|
return this.$store.state.player
|
||||||
},
|
},
|
||||||
settings_option_show_composer_for_genre() {
|
setting_show_composer_for_genre() {
|
||||||
return this.$store.getters.settings_option_show_composer_for_genre
|
return this.$store.getters.setting_show_composer_for_genre
|
||||||
},
|
},
|
||||||
settings_option_show_composer_now_playing() {
|
setting_show_composer_now_playing() {
|
||||||
return this.$store.getters.settings_option_show_composer_now_playing
|
return this.$store.getters.setting_show_composer_now_playing
|
||||||
},
|
},
|
||||||
settings_option_show_filepath_now_playing() {
|
setting_show_filepath_now_playing() {
|
||||||
return this.$store.getters.settings_option_show_filepath_now_playing
|
return this.$store.getters.setting_show_filepath_now_playing
|
||||||
},
|
},
|
||||||
track() {
|
track() {
|
||||||
return this.$store.getters.now_playing
|
return this.$store.getters.now_playing
|
||||||
|
@ -66,7 +66,7 @@ export default {
|
|||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
playlists() {
|
playlists() {
|
||||||
this.playlists_list.group({
|
return this.playlists_list.group({
|
||||||
filters: [
|
filters: [
|
||||||
(playlist) =>
|
(playlist) =>
|
||||||
playlist.folder ||
|
playlist.folder ||
|
||||||
@ -75,7 +75,6 @@ export default {
|
|||||||
playlist.item_count > playlist.stream_count
|
playlist.item_count > playlist.stream_count
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
return this.playlists_list
|
|
||||||
},
|
},
|
||||||
radio_playlists() {
|
radio_playlists() {
|
||||||
return this.$store.state.config.radio_playlists
|
return this.$store.state.config.radio_playlists
|
||||||
|
@ -34,7 +34,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #no-more> </template>
|
<template #no-more>
|
||||||
|
<br />
|
||||||
|
</template>
|
||||||
</VueEternalLoading>
|
</VueEternalLoading>
|
||||||
<modal-dialog-playlist-spotify
|
<modal-dialog-playlist-spotify
|
||||||
:item="playlist"
|
:item="playlist"
|
||||||
|
@ -3,7 +3,9 @@
|
|||||||
<content-with-hero>
|
<content-with-hero>
|
||||||
<template #heading-left>
|
<template #heading-left>
|
||||||
<h1 class="title is-5" v-text="album.name" />
|
<h1 class="title is-5" v-text="album.name" />
|
||||||
<h2 class="subtitle is-6"> </h2>
|
<h2 class="subtitle is-6">
|
||||||
|
<br />
|
||||||
|
</h2>
|
||||||
<div class="buttons fd-is-centered-mobile mt-5">
|
<div class="buttons fd-is-centered-mobile mt-5">
|
||||||
<a class="button is-small is-dark is-rounded" @click="play">
|
<a class="button is-small is-dark is-rounded" @click="play">
|
||||||
<mdicon class="icon" name="play" size="16" />
|
<mdicon class="icon" name="play" size="16" />
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<content-with-heading v-if="new_episodes.items.length > 0">
|
<content-with-heading v-if="tracks.items.length > 0">
|
||||||
<template #heading-left>
|
<template #heading-left>
|
||||||
<p class="title is-4" v-text="$t('page.podcasts.new-episodes')" />
|
<p class="title is-4" v-text="$t('page.podcasts.new-episodes')" />
|
||||||
</template>
|
</template>
|
||||||
@ -14,7 +14,7 @@
|
|||||||
</template>
|
</template>
|
||||||
<template #content>
|
<template #content>
|
||||||
<list-tracks
|
<list-tracks
|
||||||
:items="new_episodes"
|
:items="tracks"
|
||||||
:show_progress="true"
|
:show_progress="true"
|
||||||
@play-count-changed="reload_new_episodes"
|
@play-count-changed="reload_new_episodes"
|
||||||
/>
|
/>
|
||||||
@ -75,7 +75,7 @@ const dataObject = {
|
|||||||
|
|
||||||
set(vm, response) {
|
set(vm, response) {
|
||||||
vm.albums = new GroupedList(response[0].data)
|
vm.albums = new GroupedList(response[0].data)
|
||||||
vm.new_episodes = new GroupedList(response[1].data.tracks)
|
vm.tracks = new GroupedList(response[1].data.tracks)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -97,8 +97,7 @@ export default {
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
albums: [],
|
albums: [],
|
||||||
new_episodes: { items: [] },
|
tracks: { items: [] },
|
||||||
|
|
||||||
show_url_modal: false
|
show_url_modal: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -111,10 +110,10 @@ export default {
|
|||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
mark_all_played() {
|
mark_all_played() {
|
||||||
this.new_episodes.items.forEach((ep) => {
|
this.tracks.items.forEach((ep) => {
|
||||||
webapi.library_track_update(ep.id, { play_count: 'increment' })
|
webapi.library_track_update(ep.id, { play_count: 'increment' })
|
||||||
})
|
})
|
||||||
this.new_episodes.items = {}
|
this.tracks.items = {}
|
||||||
},
|
},
|
||||||
|
|
||||||
open_add_podcast_dialog() {
|
open_add_podcast_dialog() {
|
||||||
@ -123,7 +122,7 @@ export default {
|
|||||||
|
|
||||||
reload_new_episodes() {
|
reload_new_episodes() {
|
||||||
webapi.library_podcasts_new_episodes().then(({ data }) => {
|
webapi.library_podcasts_new_episodes().then(({ data }) => {
|
||||||
this.new_episodes = new GroupedList(data.tracks)
|
this.tracks = new GroupedList(data.tracks)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -150,7 +150,7 @@ export default {
|
|||||||
get() {
|
get() {
|
||||||
return this.$store.state.queue.items
|
return this.$store.state.queue.items
|
||||||
},
|
},
|
||||||
set(value) {
|
set() {
|
||||||
/* Do nothing? Send move request in @end event */
|
/* Do nothing? Send move request in @end event */
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -163,11 +163,11 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
move_item(e) {
|
move_item(event) {
|
||||||
const oldPosition =
|
const oldPosition =
|
||||||
e.oldIndex + (this.show_only_next_items && this.current_position)
|
event.oldIndex + (this.show_only_next_items && this.current_position)
|
||||||
const item = this.queue_items[oldPosition]
|
const item = this.queue_items[oldPosition]
|
||||||
const newPosition = item.position + (e.newIndex - e.oldIndex)
|
const newPosition = item.position + (event.newIndex - event.oldIndex)
|
||||||
if (newPosition !== oldPosition) {
|
if (newPosition !== oldPosition) {
|
||||||
webapi.queue_move(item.id, newPosition)
|
webapi.queue_move(item.id, newPosition)
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,9 @@
|
|||||||
keypath="page.search.help"
|
keypath="page.search.help"
|
||||||
scope="global"
|
scope="global"
|
||||||
>
|
>
|
||||||
<template #query><code>query:</code></template>
|
<template #query>
|
||||||
|
<code>query:</code>
|
||||||
|
</template>
|
||||||
<template #help>
|
<template #help>
|
||||||
<a
|
<a
|
||||||
href="https://owntone.github.io/owntone-server/smart-playlists/"
|
href="https://owntone.github.io/owntone-server/smart-playlists/"
|
||||||
@ -37,7 +39,7 @@
|
|||||||
<div v-for="query in recent_searches" :key="query" class="control">
|
<div v-for="query in recent_searches" :key="query" class="control">
|
||||||
<div class="tags has-addons">
|
<div class="tags has-addons">
|
||||||
<a class="tag" @click="open_search(query)" v-text="query" />
|
<a class="tag" @click="open_search(query)" v-text="query" />
|
||||||
<a class="tag is-delete" @click="remove_search(query)"></a>
|
<a class="tag is-delete" @click="remove_search(query)" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
<div v-for="query in recent_searches" :key="query" class="control">
|
<div v-for="query in recent_searches" :key="query" class="control">
|
||||||
<div class="tags has-addons">
|
<div class="tags has-addons">
|
||||||
<a class="tag" @click="open_search(query)" v-text="query" />
|
<a class="tag" @click="open_search(query)" v-text="query" />
|
||||||
<a class="tag is-delete" @click="remove_search(query)"></a>
|
<a class="tag is-delete" @click="remove_search(query)" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -46,7 +46,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #no-more> </template>
|
<template #no-more>
|
||||||
|
<br />
|
||||||
|
</template>
|
||||||
</VueEternalLoading>
|
</VueEternalLoading>
|
||||||
</template>
|
</template>
|
||||||
<template v-if="!expanded" #footer>
|
<template v-if="!expanded" #footer>
|
||||||
|
@ -16,8 +16,8 @@
|
|||||||
/>
|
/>
|
||||||
<settings-checkbox
|
<settings-checkbox
|
||||||
v-if="spotify.spotify_logged_in"
|
v-if="spotify.spotify_logged_in"
|
||||||
category_name="artwork"
|
category="artwork"
|
||||||
option_name="use_artwork_source_spotify"
|
name="use_artwork_source_spotify"
|
||||||
>
|
>
|
||||||
<template #label>
|
<template #label>
|
||||||
<span v-text="$t('page.settings.artwork.spotify')" />
|
<span v-text="$t('page.settings.artwork.spotify')" />
|
||||||
@ -26,10 +26,7 @@
|
|||||||
</a>
|
</a>
|
||||||
</template>
|
</template>
|
||||||
</settings-checkbox>
|
</settings-checkbox>
|
||||||
<settings-checkbox
|
<settings-checkbox category="artwork" name="use_artwork_source_discogs">
|
||||||
category_name="artwork"
|
|
||||||
option_name="use_artwork_source_discogs"
|
|
||||||
>
|
|
||||||
<template #label>
|
<template #label>
|
||||||
<span v-text="$t('page.settings.artwork.discogs')" />
|
<span v-text="$t('page.settings.artwork.discogs')" />
|
||||||
<a href="https://www.discogs.com/" target="_blank">
|
<a href="https://www.discogs.com/" target="_blank">
|
||||||
@ -38,8 +35,8 @@
|
|||||||
</template>
|
</template>
|
||||||
</settings-checkbox>
|
</settings-checkbox>
|
||||||
<settings-checkbox
|
<settings-checkbox
|
||||||
category_name="artwork"
|
category="artwork"
|
||||||
option_name="use_artwork_source_coverartarchive"
|
name="use_artwork_source_coverartarchive"
|
||||||
>
|
>
|
||||||
<template #label>
|
<template #label>
|
||||||
<span v-text="$t('page.settings.artwork.coverartarchive')" />
|
<span v-text="$t('page.settings.artwork.coverartarchive')" />
|
||||||
|
@ -26,57 +26,45 @@
|
|||||||
v-text="$t('page.settings.general.navigation-item-selection-info')"
|
v-text="$t('page.settings.general.navigation-item-selection-info')"
|
||||||
/>
|
/>
|
||||||
<settings-checkbox
|
<settings-checkbox
|
||||||
category_name="webinterface"
|
category="webinterface"
|
||||||
option_name="show_menu_item_playlists"
|
name="show_menu_item_playlists"
|
||||||
>
|
>
|
||||||
<template #label>
|
<template #label>
|
||||||
<span v-text="$t('page.settings.general.playlists')" />
|
<span v-text="$t('page.settings.general.playlists')" />
|
||||||
</template>
|
</template>
|
||||||
</settings-checkbox>
|
</settings-checkbox>
|
||||||
<settings-checkbox
|
<settings-checkbox category="webinterface" name="show_menu_item_music">
|
||||||
category_name="webinterface"
|
|
||||||
option_name="show_menu_item_music"
|
|
||||||
>
|
|
||||||
<template #label>
|
<template #label>
|
||||||
<span v-text="$t('page.settings.general.music')" />
|
<span v-text="$t('page.settings.general.music')" />
|
||||||
</template>
|
</template>
|
||||||
</settings-checkbox>
|
</settings-checkbox>
|
||||||
<settings-checkbox
|
<settings-checkbox
|
||||||
category_name="webinterface"
|
category="webinterface"
|
||||||
option_name="show_menu_item_podcasts"
|
name="show_menu_item_podcasts"
|
||||||
>
|
>
|
||||||
<template #label>
|
<template #label>
|
||||||
<span v-text="$t('page.settings.general.podcasts')" />
|
<span v-text="$t('page.settings.general.podcasts')" />
|
||||||
</template>
|
</template>
|
||||||
</settings-checkbox>
|
</settings-checkbox>
|
||||||
<settings-checkbox
|
<settings-checkbox
|
||||||
category_name="webinterface"
|
category="webinterface"
|
||||||
option_name="show_menu_item_audiobooks"
|
name="show_menu_item_audiobooks"
|
||||||
>
|
>
|
||||||
<template #label>
|
<template #label>
|
||||||
<span v-text="$t('page.settings.general.audiobooks')" />
|
<span v-text="$t('page.settings.general.audiobooks')" />
|
||||||
</template>
|
</template>
|
||||||
</settings-checkbox>
|
</settings-checkbox>
|
||||||
<settings-checkbox
|
<settings-checkbox category="webinterface" name="show_menu_item_radio">
|
||||||
category_name="webinterface"
|
|
||||||
option_name="show_menu_item_radio"
|
|
||||||
>
|
|
||||||
<template #label>
|
<template #label>
|
||||||
<span v-text="$t('page.settings.general.radio')" />
|
<span v-text="$t('page.settings.general.radio')" />
|
||||||
</template>
|
</template>
|
||||||
</settings-checkbox>
|
</settings-checkbox>
|
||||||
<settings-checkbox
|
<settings-checkbox category="webinterface" name="show_menu_item_files">
|
||||||
category_name="webinterface"
|
|
||||||
option_name="show_menu_item_files"
|
|
||||||
>
|
|
||||||
<template #label>
|
<template #label>
|
||||||
<span v-text="$t('page.settings.general.files')" />
|
<span v-text="$t('page.settings.general.files')" />
|
||||||
</template>
|
</template>
|
||||||
</settings-checkbox>
|
</settings-checkbox>
|
||||||
<settings-checkbox
|
<settings-checkbox category="webinterface" name="show_menu_item_search">
|
||||||
category_name="webinterface"
|
|
||||||
option_name="show_menu_item_search"
|
|
||||||
>
|
|
||||||
<template #label>
|
<template #label>
|
||||||
<span v-text="$t('page.settings.general.search')" />
|
<span v-text="$t('page.settings.general.search')" />
|
||||||
</template>
|
</template>
|
||||||
@ -92,8 +80,8 @@
|
|||||||
</template>
|
</template>
|
||||||
<template #content>
|
<template #content>
|
||||||
<settings-checkbox
|
<settings-checkbox
|
||||||
category_name="webinterface"
|
category="webinterface"
|
||||||
option_name="show_cover_artwork_in_album_lists"
|
name="show_cover_artwork_in_album_lists"
|
||||||
>
|
>
|
||||||
<template #label>
|
<template #label>
|
||||||
<span v-text="$t('page.settings.general.show-coverart')" />
|
<span v-text="$t('page.settings.general.show-coverart')" />
|
||||||
@ -110,8 +98,8 @@
|
|||||||
</template>
|
</template>
|
||||||
<template #content>
|
<template #content>
|
||||||
<settings-checkbox
|
<settings-checkbox
|
||||||
category_name="webinterface"
|
category="webinterface"
|
||||||
option_name="show_composer_now_playing"
|
name="show_composer_now_playing"
|
||||||
>
|
>
|
||||||
<template #label>
|
<template #label>
|
||||||
<span v-text="$t('page.settings.general.show-composer')" />
|
<span v-text="$t('page.settings.general.show-composer')" />
|
||||||
@ -121,9 +109,9 @@
|
|||||||
</template>
|
</template>
|
||||||
</settings-checkbox>
|
</settings-checkbox>
|
||||||
<settings-textfield
|
<settings-textfield
|
||||||
category_name="webinterface"
|
category="webinterface"
|
||||||
option_name="show_composer_for_genre"
|
name="show_composer_for_genre"
|
||||||
:disabled="!settings_option_show_composer_now_playing"
|
:disabled="!setting_show_composer_now_playing"
|
||||||
:placeholder="$t('page.settings.general.genres')"
|
:placeholder="$t('page.settings.general.genres')"
|
||||||
>
|
>
|
||||||
<template #label>
|
<template #label>
|
||||||
@ -145,8 +133,8 @@
|
|||||||
</template>
|
</template>
|
||||||
</settings-textfield>
|
</settings-textfield>
|
||||||
<settings-checkbox
|
<settings-checkbox
|
||||||
category_name="webinterface"
|
category="webinterface"
|
||||||
option_name="show_filepath_now_playing"
|
name="show_filepath_now_playing"
|
||||||
>
|
>
|
||||||
<template #label>
|
<template #label>
|
||||||
<span v-text="$t('page.settings.general.show-path')" />
|
<span v-text="$t('page.settings.general.show-path')" />
|
||||||
@ -162,10 +150,7 @@
|
|||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<template #content>
|
<template #content>
|
||||||
<settings-intfield
|
<settings-intfield category="webinterface" name="recently_added_limit">
|
||||||
category_name="webinterface"
|
|
||||||
option_name="recently_added_limit"
|
|
||||||
>
|
|
||||||
<template #label>
|
<template #label>
|
||||||
<span
|
<span
|
||||||
v-text="$t('page.settings.general.recently-added-page-info')"
|
v-text="$t('page.settings.general.recently-added-page-info')"
|
||||||
@ -225,11 +210,11 @@ export default {
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
settings_option_show_composer_now_playing() {
|
setting_show_composer_now_playing() {
|
||||||
return this.$store.getters.settings_option_show_composer_now_playing
|
return this.$store.getters.setting_show_composer_now_playing
|
||||||
},
|
},
|
||||||
settings_option_show_filepath_now_playing() {
|
setting_show_filepath_now_playing() {
|
||||||
return this.$store.getters.settings_option_show_filepath_now_playing
|
return this.$store.getters.setting_show_filepath_now_playing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -300,16 +300,15 @@ export const router = createRouter({
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
scrollBehavior(to, from, savedPosition) {
|
scrollBehavior(to, from, savedPosition) {
|
||||||
const wait_ms = 0
|
const delay = 0
|
||||||
if (savedPosition) {
|
if (savedPosition) {
|
||||||
// Use the saved scroll position (browser back/forward navigation)
|
// Use the saved scroll position (browser back/forward navigation)
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
resolve(savedPosition)
|
resolve(savedPosition)
|
||||||
}, wait_ms)
|
}, delay)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if (to.path === from.path && to.hash) {
|
if (to.path === from.path && to.hash) {
|
||||||
/*
|
/*
|
||||||
* Staying on the same page and jumping to an anchor (e. g. index nav)
|
* Staying on the same page and jumping to an anchor (e. g. index nav)
|
||||||
@ -318,16 +317,14 @@ export const router = createRouter({
|
|||||||
const top = to.meta.has_tabs ? TOP_WITH_TABS : TOP_WITHOUT_TABS
|
const top = to.meta.has_tabs ? TOP_WITH_TABS : TOP_WITHOUT_TABS
|
||||||
return { behavior: 'smooth', el: to.hash, top }
|
return { behavior: 'smooth', el: to.hash, top }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (to.hash) {
|
if (to.hash) {
|
||||||
// We are navigating to an anchor of a new page, add a timeout to let the transition effect finish before scrolling
|
// We are navigating to an anchor of a new page, add a timeout to let the transition effect finish before scrolling
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
resolve({ el: to.hash, top: 120 })
|
resolve({ el: to.hash, top: 120 })
|
||||||
}, wait_ms)
|
}, delay)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if (to.meta.has_index) {
|
if (to.meta.has_index) {
|
||||||
/*
|
/*
|
||||||
* Navigate to a page with index nav that should be hidden automatically
|
* Navigate to a page with index nav that should be hidden automatically
|
||||||
@ -337,7 +334,7 @@ export const router = createRouter({
|
|||||||
const top = to.meta.has_tabs ? TOP_WITH_TABS : TOP_WITHOUT_TABS
|
const top = to.meta.has_tabs ? TOP_WITH_TABS : TOP_WITHOUT_TABS
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
resolve({ el: '#top', top })
|
resolve({ el: '#top', top })
|
||||||
}, wait_ms)
|
}, delay)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,24 +70,24 @@ export default createStore({
|
|||||||
|
|
||||||
getters: {
|
getters: {
|
||||||
now_playing: (state) =>
|
now_playing: (state) =>
|
||||||
state.queue.items.find((e) => e.id === state.player.item_id) ?? {},
|
state.queue.items.find((item) => item.id === state.player.item_id) ?? {},
|
||||||
settings_option: (state) => (categoryName, optionName) =>
|
setting: (state) => (categoryName, optionName) =>
|
||||||
state.settings.categories
|
state.settings.categories
|
||||||
.find((category) => category.name === categoryName)
|
.find((category) => category.name === categoryName)
|
||||||
?.options.find((option) => option.name === optionName) ?? {},
|
?.options.find((option) => option.name === optionName) ?? {},
|
||||||
settings_option_recently_added_limit: (state, getters) =>
|
setting_recently_added_limit: (state, getters) =>
|
||||||
getters.settings_webinterface?.options.find(
|
getters.settings_webinterface?.options.find(
|
||||||
(option) => option.name === 'recently_added_limit'
|
(option) => option.name === 'recently_added_limit'
|
||||||
)?.value ?? 100,
|
)?.value ?? 100,
|
||||||
settings_option_show_composer_for_genre: (state, getters) =>
|
setting_show_composer_for_genre: (state, getters) =>
|
||||||
getters.settings_webinterface?.options.find(
|
getters.settings_webinterface?.options.find(
|
||||||
(option) => option.name === 'show_composer_for_genre'
|
(option) => option.name === 'show_composer_for_genre'
|
||||||
)?.value ?? null,
|
)?.value ?? null,
|
||||||
settings_option_show_composer_now_playing: (state, getters) =>
|
setting_show_composer_now_playing: (state, getters) =>
|
||||||
getters.settings_webinterface?.options.find(
|
getters.settings_webinterface?.options.find(
|
||||||
(option) => option.name === 'show_composer_now_playing'
|
(option) => option.name === 'show_composer_now_playing'
|
||||||
)?.value ?? false,
|
)?.value ?? false,
|
||||||
settings_option_show_filepath_now_playing: (state, getters) =>
|
setting_show_filepath_now_playing: (state, getters) =>
|
||||||
getters.settings_webinterface?.options.find(
|
getters.settings_webinterface?.options.find(
|
||||||
(option) => option.name === 'show_filepath_now_playing'
|
(option) => option.name === 'show_filepath_now_playing'
|
||||||
)?.value ?? false,
|
)?.value ?? false,
|
||||||
@ -179,7 +179,7 @@ export default createStore({
|
|||||||
},
|
},
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
add_notification({ commit, state }, notification) {
|
add_notification({ state }, notification) {
|
||||||
const newNotification = {
|
const newNotification = {
|
||||||
id: state.notifications.next_id++,
|
id: state.notifications.next_id++,
|
||||||
text: notification.text,
|
text: notification.text,
|
||||||
@ -203,7 +203,7 @@ export default createStore({
|
|||||||
}, notification.timeout)
|
}, notification.timeout)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
add_recent_search({ commit, state }, query) {
|
add_recent_search({ state }, query) {
|
||||||
const index = state.recent_searches.indexOf(query)
|
const index = state.recent_searches.indexOf(query)
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
state.recent_searches.splice(index, 1)
|
state.recent_searches.splice(index, 1)
|
||||||
@ -213,24 +213,24 @@ export default createStore({
|
|||||||
state.recent_searches.pop()
|
state.recent_searches.pop()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
delete_notification({ commit, state }, notification) {
|
delete_notification({ state }, notification) {
|
||||||
const index = state.notifications.list.indexOf(notification)
|
const index = state.notifications.list.indexOf(notification)
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
state.notifications.list.splice(index, 1)
|
state.notifications.list.splice(index, 1)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
remove_recent_search({ commit, state }, query) {
|
remove_recent_search({ state }, query) {
|
||||||
const index = state.recent_searches.indexOf(query)
|
const index = state.recent_searches.indexOf(query)
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
state.recent_searches.splice(index, 1)
|
state.recent_searches.splice(index, 1)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
update_settings_option({ commit, state }, option) {
|
update_setting({ state }, option) {
|
||||||
const settingCategory = state.settings.categories.find(
|
const settingCategory = state.settings.categories.find(
|
||||||
(e) => e.name === option.category
|
(category) => category.name === option.category
|
||||||
),
|
),
|
||||||
settingOption = settingCategory.options.find(
|
settingOption = settingCategory.options.find(
|
||||||
(e) => e.name === option.name
|
(setting) => setting.name === option.name
|
||||||
)
|
)
|
||||||
settingOption.value = option.value
|
settingOption.value = option.value
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
<div class="columns is-centered">
|
<div class="columns is-centered">
|
||||||
<div class="column is-four-fifths">
|
<div class="column is-four-fifths">
|
||||||
<section v-if="$slots.options">
|
<section v-if="$slots.options">
|
||||||
<div ref="options_ref" style="height: 1px" />
|
<div ref="options" style="height: 1px" />
|
||||||
<slot name="options" />
|
<slot name="options" />
|
||||||
<nav class="buttons is-centered mt-4 mb-2">
|
<nav class="buttons is-centered mt-4 mb-2">
|
||||||
<router-link class="button is-small is-white" :to="position">
|
<router-link class="button is-small is-white" :to="position">
|
||||||
@ -65,12 +65,12 @@ export default {
|
|||||||
rootMargin: '-82px 0px 0px 0px',
|
rootMargin: '-82px 0px 0px 0px',
|
||||||
threshold: 1.0
|
threshold: 1.0
|
||||||
})
|
})
|
||||||
this.observer.observe(this.$refs.options_ref)
|
this.observer.observe(this.$refs.options)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
onElementObserved(entries) {
|
onElementObserved(entries) {
|
||||||
entries.forEach(({ target, isIntersecting }) => {
|
entries.forEach(({ isIntersecting }) => {
|
||||||
this.options_visible = isIntersecting
|
this.options_visible = isIntersecting
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
@ -9,37 +9,31 @@ import vue from '@vitejs/plugin-vue'
|
|||||||
*
|
*
|
||||||
* export VITE_OWNTONE_URL=http://owntone.local:3689; npm run serve
|
* export VITE_OWNTONE_URL=http://owntone.local:3689; npm run serve
|
||||||
*/
|
*/
|
||||||
const owntoneUrl = process.env.VITE_OWNTONE_URL ?? 'http://localhost:3689'
|
const target = process.env.VITE_OWNTONE_URL ?? 'http://localhost:3689'
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
resolve: { alias: { '@': '/src' } },
|
build: {
|
||||||
|
outDir: '../htdocs',
|
||||||
|
rollupOptions: {
|
||||||
|
output: {
|
||||||
|
assetFileNames: `assets/[name].[ext]`,
|
||||||
|
chunkFileNames: `assets/[name].js`,
|
||||||
|
entryFileNames: `assets/[name].js`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
vue(),
|
vue(),
|
||||||
i18n({
|
i18n({
|
||||||
include: path.resolve(__dirname, './src/i18n/**.json')
|
include: path.resolve(__dirname, './src/i18n/**.json')
|
||||||
})
|
})
|
||||||
],
|
],
|
||||||
build: {
|
resolve: { alias: { '@': '/src' } },
|
||||||
outDir: '../htdocs',
|
|
||||||
rollupOptions: {
|
|
||||||
output: {
|
|
||||||
entryFileNames: `assets/[name].js`,
|
|
||||||
chunkFileNames: `assets/[name].js`,
|
|
||||||
assetFileNames: `assets/[name].[ext]`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
server: {
|
server: {
|
||||||
proxy: {
|
proxy: {
|
||||||
'/api': {
|
'/api': { target },
|
||||||
target: owntoneUrl
|
'/artwork': { target },
|
||||||
},
|
'/stream.mp3': { target }
|
||||||
'/artwork': {
|
|
||||||
target: owntoneUrl
|
|
||||||
},
|
|
||||||
'/stream.mp3': {
|
|
||||||
target: owntoneUrl
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
Loading…
Reference in New Issue
Block a user