mirror of
https://github.com/owntone/owntone-server.git
synced 2025-04-14 08:16:17 -04:00
[web] Switch to camel case
This commit is contained in:
parent
6c09457e5d
commit
7e8672917e
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
15
web-src/package-lock.json
generated
15
web-src/package-lock.json
generated
@ -518,9 +518,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint-community/eslint-utils": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.5.0.tgz",
|
||||
"integrity": "sha512-RoV8Xs9eNwiDvhv7M+xcL4PWyRyIXRY/FLp3buU4h1EYfdF7unWUy3dOjPqb3C7rMUewIcqwW850PgS8h1o1yg==",
|
||||
"version": "4.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.5.1.tgz",
|
||||
"integrity": "sha512-soEIOALTfTK6EjmKMMoLugwaP0rzkad90iIWd1hMO9ARkSAyjfMfkRRhLvD5qH7vvM0Cg72pieUfR6yh6XxC4w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@ -1960,12 +1960,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "1.8.2",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.8.2.tgz",
|
||||
"integrity": "sha512-ls4GYBm5aig9vWx8AWDSGLpnpDQRtWAfrjU+EuytuODrFBkqesN2RkOQCBzrA1RQNHw1SmRMSDDDSwzNAYQ6Rg==",
|
||||
"version": "1.8.2",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.8.2.tgz",
|
||||
"integrity": "sha512-ls4GYBm5aig9vWx8AWDSGLpnpDQRtWAfrjU+EuytuODrFBkqesN2RkOQCBzrA1RQNHw1SmRMSDDDSwzNAYQ6Rg==",
|
||||
"version": "1.8.3",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.8.3.tgz",
|
||||
"integrity": "sha512-iP4DebzoNlP/YN2dpwCgb8zoCmhtkajzS48JvwmkSkXvPI3DHc7m+XYL5tGnSlJtR6nImXZmdCuN5aP8dh1d8A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.15.6",
|
||||
|
@ -5,8 +5,8 @@
|
||||
<component :is="Component" />
|
||||
</router-view>
|
||||
<modal-dialog-remote-pairing
|
||||
:show="pairing_active"
|
||||
@close="pairing_active = false"
|
||||
:show="pairingActive"
|
||||
@close="pairingActive = false"
|
||||
/>
|
||||
<modal-dialog-update
|
||||
:show="showUpdateDialog"
|
||||
@ -67,9 +67,9 @@ export default {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
pairing_active: false,
|
||||
pairingActive: false,
|
||||
reconnect_attempts: 0,
|
||||
token_timer_id: 0
|
||||
timerId: 0
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@ -100,10 +100,10 @@ export default {
|
||||
},
|
||||
watch: {
|
||||
showBurgerMenu() {
|
||||
this.update_is_clipped()
|
||||
this.updateClipping()
|
||||
},
|
||||
showPlayerMenu() {
|
||||
this.update_is_clipped()
|
||||
this.updateClipping()
|
||||
}
|
||||
},
|
||||
created() {
|
||||
@ -145,7 +145,7 @@ export default {
|
||||
})
|
||||
},
|
||||
openWebsocket() {
|
||||
const socket = this.create_websocket()
|
||||
const socket = this.createWebsocket()
|
||||
const vm = this
|
||||
socket.onopen = () => {
|
||||
vm.reconnect_attempts = 0
|
||||
@ -165,14 +165,14 @@ export default {
|
||||
]
|
||||
})
|
||||
)
|
||||
vm.update_outputs()
|
||||
vm.update_player_status()
|
||||
vm.update_library_stats()
|
||||
vm.update_settings()
|
||||
vm.update_queue()
|
||||
vm.update_spotify()
|
||||
vm.update_lastfm()
|
||||
vm.update_pairing()
|
||||
vm.updateOutputs()
|
||||
vm.updatePlayerStatus()
|
||||
vm.updateLibraryStats()
|
||||
vm.updateSettings()
|
||||
vm.updateQueue()
|
||||
vm.updateSpotify()
|
||||
vm.updateLastfm()
|
||||
vm.updatePairing()
|
||||
}
|
||||
|
||||
/*
|
||||
@ -181,23 +181,23 @@ export default {
|
||||
* There are two relevant events - focus and visibilitychange, so we
|
||||
* throttle the updates to avoid multiple redundant updates.
|
||||
*/
|
||||
let update_throttled = false
|
||||
let updateThrottled = false
|
||||
|
||||
const update_info = () => {
|
||||
if (update_throttled) {
|
||||
const updateInfo = () => {
|
||||
if (updateThrottled) {
|
||||
return
|
||||
}
|
||||
vm.update_outputs()
|
||||
vm.update_player_status()
|
||||
vm.update_library_stats()
|
||||
vm.update_settings()
|
||||
vm.update_queue()
|
||||
vm.update_spotify()
|
||||
vm.update_lastfm()
|
||||
vm.update_pairing()
|
||||
update_throttled = true
|
||||
vm.updateOutputs()
|
||||
vm.updatePlayerStatus()
|
||||
vm.updateLibraryStats()
|
||||
vm.updateSettings()
|
||||
vm.updateQueue()
|
||||
vm.updateSpotify()
|
||||
vm.updateLastfm()
|
||||
vm.updatePairing()
|
||||
updateThrottled = true
|
||||
setTimeout(() => {
|
||||
update_throttled = false
|
||||
updateThrottled = false
|
||||
}, 500)
|
||||
}
|
||||
|
||||
@ -205,10 +205,10 @@ export default {
|
||||
* These events are fired when the window becomes active in different
|
||||
* ways. When this happens, we should update 'now playing' info, etc.
|
||||
*/
|
||||
window.addEventListener('focus', update_info)
|
||||
window.addEventListener('focus', updateInfo)
|
||||
document.addEventListener('visibilitychange', () => {
|
||||
if (document.visibilityState === 'visible') {
|
||||
update_info()
|
||||
updateInfo()
|
||||
}
|
||||
})
|
||||
|
||||
@ -218,33 +218,33 @@ export default {
|
||||
data.notify.includes('update') ||
|
||||
data.notify.includes('database')
|
||||
) {
|
||||
vm.update_library_stats()
|
||||
vm.updateLibraryStats()
|
||||
}
|
||||
if (
|
||||
data.notify.includes('player') ||
|
||||
data.notify.includes('options') ||
|
||||
data.notify.includes('volume')
|
||||
) {
|
||||
vm.update_player_status()
|
||||
vm.updatePlayerStatus()
|
||||
}
|
||||
if (data.notify.includes('outputs') || data.notify.includes('volume')) {
|
||||
vm.update_outputs()
|
||||
vm.updateOutputs()
|
||||
}
|
||||
if (data.notify.includes('queue')) {
|
||||
vm.update_queue()
|
||||
vm.updateQueue()
|
||||
}
|
||||
if (data.notify.includes('spotify')) {
|
||||
vm.update_spotify()
|
||||
vm.updateSpotify()
|
||||
}
|
||||
if (data.notify.includes('lastfm')) {
|
||||
vm.update_lastfm()
|
||||
vm.updateLastfm()
|
||||
}
|
||||
if (data.notify.includes('pairing')) {
|
||||
vm.update_pairing()
|
||||
vm.updatePairing()
|
||||
}
|
||||
}
|
||||
},
|
||||
create_websocket() {
|
||||
createWebsocket() {
|
||||
const protocol = window.location.protocol.replace('http', 'ws')
|
||||
const hostname =
|
||||
(import.meta.env.DEV &&
|
||||
@ -258,19 +258,19 @@ export default {
|
||||
reconnectInterval: 1000
|
||||
})
|
||||
},
|
||||
update_is_clipped() {
|
||||
updateClipping() {
|
||||
if (this.showBurgerMenu || this.showPlayerMenu) {
|
||||
document.querySelector('html').classList.add('is-clipped')
|
||||
} else {
|
||||
document.querySelector('html').classList.remove('is-clipped')
|
||||
}
|
||||
},
|
||||
update_lastfm() {
|
||||
updateLastfm() {
|
||||
webapi.lastfm().then(({ data }) => {
|
||||
this.servicesStore.lastfm = data
|
||||
})
|
||||
},
|
||||
update_library_stats() {
|
||||
updateLibraryStats() {
|
||||
webapi.library_stats().then(({ data }) => {
|
||||
this.libraryStore.$state = data
|
||||
})
|
||||
@ -278,7 +278,7 @@ export default {
|
||||
this.libraryStore.rss = data
|
||||
})
|
||||
},
|
||||
update_lyrics() {
|
||||
updateLyrics() {
|
||||
const track = this.queueStore.current
|
||||
if (track?.track_id) {
|
||||
webapi.library_track(track.track_id).then(({ data }) => {
|
||||
@ -288,44 +288,44 @@ export default {
|
||||
this.lyricsStore.$reset()
|
||||
}
|
||||
},
|
||||
update_outputs() {
|
||||
updateOutputs() {
|
||||
webapi.outputs().then(({ data }) => {
|
||||
this.outputsStore.outputs = data.outputs
|
||||
})
|
||||
},
|
||||
update_pairing() {
|
||||
updatePairing() {
|
||||
webapi.pairing().then(({ data }) => {
|
||||
this.remotesStore.$state = data
|
||||
this.pairing_active = data.active
|
||||
this.pairingActive = data.active
|
||||
})
|
||||
},
|
||||
update_player_status() {
|
||||
updatePlayerStatus() {
|
||||
webapi.player_status().then(({ data }) => {
|
||||
this.playerStore.$state = data
|
||||
this.update_lyrics()
|
||||
this.updateLyrics()
|
||||
})
|
||||
},
|
||||
update_queue() {
|
||||
updateQueue() {
|
||||
webapi.queue().then(({ data }) => {
|
||||
this.queueStore.$state = data
|
||||
this.update_lyrics()
|
||||
this.updateLyrics()
|
||||
})
|
||||
},
|
||||
update_settings() {
|
||||
updateSettings() {
|
||||
webapi.settings().then(({ data }) => {
|
||||
this.settingsStore.$state = data
|
||||
})
|
||||
},
|
||||
update_spotify() {
|
||||
updateSpotify() {
|
||||
webapi.spotify().then(({ data }) => {
|
||||
this.servicesStore.spotify = data
|
||||
if (this.token_timer_id > 0) {
|
||||
window.clearTimeout(this.token_timer_id)
|
||||
this.token_timer_id = 0
|
||||
if (this.timerId > 0) {
|
||||
window.clearTimeout(this.timerId)
|
||||
this.timerId = 0
|
||||
}
|
||||
if (data.webapi_token_expires_in > 0 && data.webapi_token) {
|
||||
this.token_timer_id = window.setTimeout(
|
||||
this.update_spotify,
|
||||
this.timerId = window.setTimeout(
|
||||
this.updateSpotify,
|
||||
1000 * data.webapi_token_expires_in
|
||||
)
|
||||
}
|
||||
|
@ -1,75 +1,48 @@
|
||||
<template>
|
||||
<template v-for="item in items" :key="item.itemId">
|
||||
<div v-if="!item.isItem" class="py-5">
|
||||
<span
|
||||
:id="`index_${item.index}`"
|
||||
class="tag is-small has-text-weight-bold"
|
||||
v-text="item.index"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-else
|
||||
class="media is-align-items-center is-clickable mb-0"
|
||||
@click="open(item.item)"
|
||||
>
|
||||
<control-image
|
||||
v-if="settingsStore.show_cover_artwork_in_album_lists"
|
||||
:url="item.item.artwork_url"
|
||||
:artist="item.item.artist"
|
||||
:album="item.item.name"
|
||||
class="media-left is-small"
|
||||
/>
|
||||
<div class="media-content">
|
||||
<div class="is-size-6 has-text-weight-bold" v-text="item.item.name" />
|
||||
<div
|
||||
class="is-size-7 has-text-grey has-text-weight-bold"
|
||||
v-text="item.item.artist"
|
||||
/>
|
||||
<div
|
||||
v-if="item.item.date_released && item.item.media_kind === 'music'"
|
||||
class="is-size-7 has-text-grey"
|
||||
v-text="$filters.toDate(item.item.date_released)"
|
||||
/>
|
||||
</div>
|
||||
<div class="media-right">
|
||||
<a @click.prevent.stop="openDialog(item.item)">
|
||||
<mdicon class="icon has-text-grey" name="dots-vertical" size="16" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<teleport to="#app">
|
||||
<modal-dialog-album
|
||||
:item="selectedItem"
|
||||
:media_kind="media_kind"
|
||||
:show="showDetailsModal"
|
||||
@close="showDetailsModal = false"
|
||||
@remove-podcast="openRemovePodcastDialog()"
|
||||
@play-count-changed="onPlayCountChange()"
|
||||
/>
|
||||
<modal-dialog
|
||||
:actions="actions"
|
||||
:show="showRemovePodcastModal"
|
||||
:title="$t('page.podcast.remove-podcast')"
|
||||
@cancel="showRemovePodcastModal = false"
|
||||
@remove="removePodcast"
|
||||
>
|
||||
<template #content>
|
||||
<i18n-t keypath="list.albums.info" tag="p" scope="global">
|
||||
<template #separator>
|
||||
<br />
|
||||
</template>
|
||||
<template #name>
|
||||
<b v-text="rss_playlist_to_remove.name" />
|
||||
</template>
|
||||
</i18n-t>
|
||||
</template>
|
||||
</modal-dialog>
|
||||
</teleport>
|
||||
<list-item
|
||||
v-for="item in items"
|
||||
:key="item.itemId"
|
||||
:is-item="item.isItem"
|
||||
:image="url(item)"
|
||||
:index="item.index"
|
||||
:lines="[
|
||||
item.item.name,
|
||||
item.item.artist,
|
||||
$filters.toDate(item.item.date_released)
|
||||
]"
|
||||
@open="open(item.item)"
|
||||
@open-details="openDetails(item.item)"
|
||||
/>
|
||||
<modal-dialog-album
|
||||
:item="selectedItem"
|
||||
:media_kind="media_kind"
|
||||
:show="showDetailsModal"
|
||||
@close="showDetailsModal = false"
|
||||
@remove-podcast="openRemovePodcastDialog()"
|
||||
@play-count-changed="onPlayCountChange()"
|
||||
/>
|
||||
<modal-dialog
|
||||
:actions="actions"
|
||||
:show="showRemovePodcastModal"
|
||||
:title="$t('page.podcast.remove-podcast')"
|
||||
@cancel="showRemovePodcastModal = false"
|
||||
@remove="removePodcast"
|
||||
>
|
||||
<template #content>
|
||||
<i18n-t keypath="list.albums.info" tag="p" scope="global">
|
||||
<template #separator>
|
||||
<br />
|
||||
</template>
|
||||
<template #name>
|
||||
<b v-text="playlistToRemove.name" />
|
||||
</template>
|
||||
</i18n-t>
|
||||
</template>
|
||||
</modal-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ControlImage from '@/components/ControlImage.vue'
|
||||
import ListItem from '@/components/ListItem.vue'
|
||||
import ModalDialog from '@/components/ModalDialog.vue'
|
||||
import ModalDialogAlbum from '@/components/ModalDialogAlbum.vue'
|
||||
import { useSettingsStore } from '@/stores/settings'
|
||||
@ -77,7 +50,7 @@ import webapi from '@/webapi'
|
||||
|
||||
export default {
|
||||
name: 'ListAlbums',
|
||||
components: { ControlImage, ModalDialog, ModalDialogAlbum },
|
||||
components: { ListItem, ModalDialog, ModalDialogAlbum },
|
||||
props: {
|
||||
items: { required: true, type: Object },
|
||||
media_kind: { default: '', type: String }
|
||||
@ -88,7 +61,7 @@ export default {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
rss_playlist_to_remove: {},
|
||||
playlistToRemove: {},
|
||||
selectedItem: {},
|
||||
showDetailsModal: false,
|
||||
showRemovePodcastModal: false
|
||||
@ -119,7 +92,7 @@ export default {
|
||||
this.$router.push({ name: 'music-album', params: { id: item.id } })
|
||||
}
|
||||
},
|
||||
openDialog(item) {
|
||||
openDetails(item) {
|
||||
this.selectedItem = item
|
||||
this.showDetailsModal = true
|
||||
},
|
||||
@ -128,7 +101,7 @@ export default {
|
||||
.library_album_tracks(this.selectedItem.id, { limit: 1 })
|
||||
.then(({ data: album }) => {
|
||||
webapi.library_track_playlists(album.items[0].id).then(({ data }) => {
|
||||
;[this.rss_playlist_to_remove] = data.items.filter(
|
||||
;[this.playlistToRemove] = data.items.filter(
|
||||
(playlist) => playlist.type === 'rss'
|
||||
)
|
||||
this.showRemovePodcastModal = true
|
||||
@ -141,11 +114,15 @@ export default {
|
||||
},
|
||||
removePodcast() {
|
||||
this.showRemovePodcastModal = false
|
||||
webapi
|
||||
.library_playlist_delete(this.rss_playlist_to_remove.id)
|
||||
.then(() => {
|
||||
this.$emit('podcast-deleted')
|
||||
})
|
||||
webapi.library_playlist_delete(this.playlistToRemove.id).then(() => {
|
||||
this.$emit('podcast-deleted')
|
||||
})
|
||||
},
|
||||
url(item) {
|
||||
if (this.settingsStore.show_cover_artwork_in_album_lists) {
|
||||
return item.item.artwork_url
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,51 +1,33 @@
|
||||
<template>
|
||||
<template v-for="item in items" :key="item.id">
|
||||
<div
|
||||
class="media is-align-items-center is-clickable mb-0"
|
||||
@click="open(item)"
|
||||
>
|
||||
<control-image
|
||||
v-if="settingsStore.show_cover_artwork_in_album_lists"
|
||||
:url="item.images?.[0]?.url ?? ''"
|
||||
:artist="item.artist"
|
||||
:album="item.name"
|
||||
class="media-left is-small"
|
||||
/>
|
||||
<div class="media-content">
|
||||
<div class="is-size-6 has-text-weight-bold" v-text="item.name" />
|
||||
<div
|
||||
class="is-size-7 has-text-weight-bold has-text-grey"
|
||||
v-text="item.artists[0]?.name"
|
||||
/>
|
||||
<div
|
||||
class="is-size-7 has-text-grey"
|
||||
v-text="$filters.toDate(item.release_date)"
|
||||
/>
|
||||
</div>
|
||||
<div class="media-right">
|
||||
<a @click.prevent.stop="openDialog(item)">
|
||||
<mdicon class="icon has-text-grey" name="dots-vertical" size="16" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<teleport to="#app">
|
||||
<modal-dialog-album-spotify
|
||||
:item="selectedItem"
|
||||
:show="showDetailsModal"
|
||||
@close="showDetailsModal = false"
|
||||
/>
|
||||
</teleport>
|
||||
<list-item
|
||||
v-for="item in items"
|
||||
:key="item.id"
|
||||
:is-item="item.isItem"
|
||||
:image="url(item)"
|
||||
:index="item.index"
|
||||
:lines="[
|
||||
item.name,
|
||||
item.artists[0]?.name,
|
||||
$filters.toDate(item.release_date)
|
||||
]"
|
||||
@open="open(item)"
|
||||
@open-details="openDetails(item)"
|
||||
/>
|
||||
<modal-dialog-album-spotify
|
||||
:item="selectedItem"
|
||||
:show="showDetailsModal"
|
||||
@close="showDetailsModal = false"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ControlImage from '@/components/ControlImage.vue'
|
||||
import ListItem from '@/components/ListItem.vue'
|
||||
import ModalDialogAlbumSpotify from '@/components/ModalDialogAlbumSpotify.vue'
|
||||
import { useSettingsStore } from '@/stores/settings'
|
||||
|
||||
export default {
|
||||
name: 'ListAlbumsSpotify',
|
||||
components: { ControlImage, ModalDialogAlbumSpotify },
|
||||
components: { ListItem, ModalDialogAlbumSpotify },
|
||||
props: { items: { required: true, type: Object } },
|
||||
setup() {
|
||||
return { settingsStore: useSettingsStore() }
|
||||
@ -60,9 +42,15 @@ export default {
|
||||
params: { id: item.id }
|
||||
})
|
||||
},
|
||||
openDialog(item) {
|
||||
openDetails(item) {
|
||||
this.selectedItem = item
|
||||
this.showDetailsModal = true
|
||||
},
|
||||
url(item) {
|
||||
if (this.settingsStore.show_cover_artwork_in_album_lists) {
|
||||
return item.images?.[0]?.url ?? ''
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,48 +1,31 @@
|
||||
<template>
|
||||
<template v-for="item in items" :key="item.itemId">
|
||||
<div v-if="!item.isItem" class="py-5">
|
||||
<span
|
||||
:id="`index_${item.index}`"
|
||||
class="tag is-small has-text-weight-bold"
|
||||
v-text="item.index"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-else
|
||||
class="media is-align-items-center is-clickable mb-0"
|
||||
@click="open(item.item)"
|
||||
>
|
||||
<div class="media-content">
|
||||
<p class="is-size-6 has-text-weight-bold" v-text="item.item.name" />
|
||||
</div>
|
||||
<div class="media-right">
|
||||
<a @click.prevent.stop="openDialog(item.item)">
|
||||
<mdicon class="icon has-text-grey" name="dots-vertical" size="16" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<teleport to="#app">
|
||||
<modal-dialog-artist
|
||||
:item="selectedItem"
|
||||
:show="showDetailsModal"
|
||||
@close="showDetailsModal = false"
|
||||
/>
|
||||
</teleport>
|
||||
<list-item
|
||||
v-for="item in items"
|
||||
:key="item.itemId"
|
||||
:is-item="item.isItem"
|
||||
:index="item.index"
|
||||
:lines="[item.item.name]"
|
||||
@open="open(item.item)"
|
||||
@open-details="openDetails(item.item)"
|
||||
/>
|
||||
<modal-dialog-artist
|
||||
:item="selectedItem"
|
||||
:show="showDetailsModal"
|
||||
@close="showDetailsModal = false"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ListItem from '@/components/ListItem.vue'
|
||||
import ModalDialogArtist from '@/components/ModalDialogArtist.vue'
|
||||
|
||||
export default {
|
||||
name: 'ListArtists',
|
||||
components: { ModalDialogArtist },
|
||||
components: { ListItem, ModalDialogArtist },
|
||||
props: { items: { required: true, type: Object } },
|
||||
|
||||
data() {
|
||||
return { selectedItem: {}, showDetailsModal: false }
|
||||
},
|
||||
|
||||
methods: {
|
||||
open(item) {
|
||||
this.selectedItem = item
|
||||
@ -50,7 +33,7 @@ export default {
|
||||
item.media_kind === 'audiobook' ? 'audiobooks-artist' : 'music-artist'
|
||||
this.$router.push({ name: route, params: { id: item.id } })
|
||||
},
|
||||
openDialog(item) {
|
||||
openDetails(item) {
|
||||
this.selectedItem = item
|
||||
this.showDetailsModal = true
|
||||
}
|
||||
|
@ -1,31 +1,27 @@
|
||||
<template>
|
||||
<template v-for="item in items" :key="item.id">
|
||||
<div class="media is-align-items-center is-clickable mb-0">
|
||||
<div class="media-content" @click="open(item)">
|
||||
<p class="is-size-6 has-text-weight-bold" v-text="item.name" />
|
||||
</div>
|
||||
<div class="media-right">
|
||||
<a @click.prevent.stop="openDialog(item)">
|
||||
<mdicon class="icon has-text-grey" name="dots-vertical" size="16" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<teleport to="#app">
|
||||
<modal-dialog-artist-spotify
|
||||
:item="selectedItem"
|
||||
:show="showDetailsModal"
|
||||
@close="showDetailsModal = false"
|
||||
/>
|
||||
</teleport>
|
||||
<list-item
|
||||
v-for="item in items"
|
||||
:key="item.id"
|
||||
:is-item="true"
|
||||
:index="item.index"
|
||||
:lines="[item.name]"
|
||||
@open="open(item)"
|
||||
@open-details="openDetails(item)"
|
||||
/>
|
||||
<modal-dialog-artist-spotify
|
||||
:item="selectedItem"
|
||||
:show="showDetailsModal"
|
||||
@close="showDetailsModal = false"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ListItem from '@/components/ListItem.vue'
|
||||
import ModalDialogArtistSpotify from '@/components/ModalDialogArtistSpotify.vue'
|
||||
|
||||
export default {
|
||||
name: 'ListArtistsSpotify',
|
||||
components: { ModalDialogArtistSpotify },
|
||||
components: { ListItem, ModalDialogArtistSpotify },
|
||||
props: { items: { required: true, type: Object } },
|
||||
|
||||
data() {
|
||||
@ -38,7 +34,7 @@ export default {
|
||||
params: { id: item.id }
|
||||
})
|
||||
},
|
||||
openDialog(item) {
|
||||
openDetails(item) {
|
||||
this.selectedItem = item
|
||||
this.showDetailsModal = true
|
||||
}
|
||||
|
@ -1,50 +1,31 @@
|
||||
<template>
|
||||
<template v-for="item in items" :key="item.itemId">
|
||||
<div v-if="!item.isItem" class="py-5">
|
||||
<div class="media-content">
|
||||
<span
|
||||
:id="`index_${item.index}`"
|
||||
class="tag is-small has-text-weight-bold"
|
||||
v-text="item.index"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-else
|
||||
class="media is-align-items-center is-clickable mb-0"
|
||||
@click="open(item.item)"
|
||||
>
|
||||
<div class="media-content">
|
||||
<p class="is-size-6 has-text-weight-bold" v-text="item.item.name" />
|
||||
</div>
|
||||
<div class="media-right">
|
||||
<a @click.prevent.stop="openDialog(item.item)">
|
||||
<mdicon class="icon has-text-grey" name="dots-vertical" size="16" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<teleport to="#app">
|
||||
<modal-dialog-composer
|
||||
:item="selectedItem"
|
||||
:show="showDetailsModal"
|
||||
@close="showDetailsModal = false"
|
||||
/>
|
||||
</teleport>
|
||||
<list-item
|
||||
v-for="item in items"
|
||||
:key="item.itemId"
|
||||
:is-item="item.isItem"
|
||||
:index="item.index"
|
||||
:lines="[item.item.name]"
|
||||
@open="open(item.item)"
|
||||
@open-details="openDetails(item.item)"
|
||||
/>
|
||||
<modal-dialog-composer
|
||||
:item="selectedItem"
|
||||
:show="showDetailsModal"
|
||||
@close="showDetailsModal = false"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ListItem from '@/components/ListItem.vue'
|
||||
import ModalDialogComposer from '@/components/ModalDialogComposer.vue'
|
||||
|
||||
export default {
|
||||
name: 'ListComposers',
|
||||
components: { ModalDialogComposer },
|
||||
components: { ListItem, ModalDialogComposer },
|
||||
props: { items: { required: true, type: Object } },
|
||||
|
||||
data() {
|
||||
return { selectedItem: {}, showDetailsModal: false }
|
||||
},
|
||||
|
||||
methods: {
|
||||
open(item) {
|
||||
this.selectedItem = item
|
||||
@ -53,8 +34,7 @@ export default {
|
||||
params: { name: item.name }
|
||||
})
|
||||
},
|
||||
|
||||
openDialog(item) {
|
||||
openDetails(item) {
|
||||
this.selectedItem = item
|
||||
this.showDetailsModal = true
|
||||
}
|
||||
|
@ -27,22 +27,20 @@
|
||||
>
|
||||
<mdicon class="media-left icon" name="folder" />
|
||||
<div class="media-content">
|
||||
<p class="is-size-6 has-text-weight-bold" v-text="item.name" />
|
||||
<div class="is-size-6 has-text-weight-bold" v-text="item.name" />
|
||||
</div>
|
||||
<div class="media-right">
|
||||
<a @click.prevent.stop="openDialog(item)">
|
||||
<a @click.prevent.stop="openDetails(item)">
|
||||
<mdicon class="icon has-text-grey" name="dots-vertical" size="16" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<teleport to="#app">
|
||||
<modal-dialog-directory
|
||||
:item="selectedItem"
|
||||
:show="showDetailsModal"
|
||||
@close="showDetailsModal = false"
|
||||
/>
|
||||
</teleport>
|
||||
<modal-dialog-directory
|
||||
:item="selectedItem"
|
||||
:show="showDetailsModal"
|
||||
@close="showDetailsModal = false"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
@ -80,7 +78,7 @@ export default {
|
||||
}
|
||||
this.$router.push(route)
|
||||
},
|
||||
openDialog(item) {
|
||||
openDetails(item) {
|
||||
this.selectedItem = item.path
|
||||
this.showDetailsModal = true
|
||||
},
|
||||
|
@ -1,45 +1,28 @@
|
||||
<template>
|
||||
<template v-for="item in items" :key="item.itemId">
|
||||
<div v-if="!item.isItem" class="py-5">
|
||||
<div class="media-content">
|
||||
<span
|
||||
:id="`index_${item.index}`"
|
||||
class="tag is-small has-text-weight-bold"
|
||||
v-text="item.index"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-else
|
||||
class="media is-align-items-center is-clickable mb-0"
|
||||
@click="open(item.item)"
|
||||
>
|
||||
<div class="media-content">
|
||||
<p class="is-size-6 has-text-weight-bold" v-text="item.item.name" />
|
||||
</div>
|
||||
<div class="media-right">
|
||||
<a @click.prevent.stop="openDialog(item.item)">
|
||||
<mdicon class="icon has-text-grey" name="dots-vertical" size="16" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<teleport to="#app">
|
||||
<modal-dialog-genre
|
||||
:item="selectedItem"
|
||||
:media_kind="media_kind"
|
||||
:show="showDetailsModal"
|
||||
@close="showDetailsModal = false"
|
||||
/>
|
||||
</teleport>
|
||||
<list-item
|
||||
v-for="item in items"
|
||||
:key="item.itemId"
|
||||
:is-item="item.isItem"
|
||||
:index="item.index"
|
||||
:lines="[item.item.name]"
|
||||
@open="open(item.item)"
|
||||
@open-details="openDetails(item.item)"
|
||||
/>
|
||||
<modal-dialog-genre
|
||||
:item="selectedItem"
|
||||
:media_kind="media_kind"
|
||||
:show="showDetailsModal"
|
||||
@close="showDetailsModal = false"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ListItem from '@/components/ListItem.vue'
|
||||
import ModalDialogGenre from '@/components/ModalDialogGenre.vue'
|
||||
|
||||
export default {
|
||||
name: 'ListGenres',
|
||||
components: { ModalDialogGenre },
|
||||
components: { ListItem, ModalDialogGenre },
|
||||
props: {
|
||||
items: { required: true, type: Object },
|
||||
media_kind: { required: true, type: String }
|
||||
@ -55,7 +38,7 @@ export default {
|
||||
query: { media_kind: this.media_kind }
|
||||
})
|
||||
},
|
||||
openDialog(item) {
|
||||
openDetails(item) {
|
||||
this.selectedItem = item
|
||||
this.showDetailsModal = true
|
||||
}
|
||||
|
80
web-src/src/components/ListItem.vue
Normal file
80
web-src/src/components/ListItem.vue
Normal file
@ -0,0 +1,80 @@
|
||||
<template>
|
||||
<div v-if="!isItem" class="py-5">
|
||||
<div class="media-content">
|
||||
<span
|
||||
:id="`index_${index}`"
|
||||
class="tag is-small has-text-weight-bold"
|
||||
v-text="index"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-else
|
||||
class="media is-align-items-center is-clickable mb-0"
|
||||
:class="{ 'with-progress': progress }"
|
||||
@click="open"
|
||||
>
|
||||
<mdicon v-if="icon" class="media-left icon" :name="icon" />
|
||||
<control-image v-if="image" :url="image" class="media-left is-small" />
|
||||
<div class="media-content">
|
||||
<div
|
||||
v-for="(line, position) in lines"
|
||||
:key="position"
|
||||
:class="{
|
||||
'is-size-6': position === 0,
|
||||
'is-size-7': position !== 0,
|
||||
'has-text-weight-bold': position !== 2,
|
||||
'has-text-grey': position !== 0
|
||||
}"
|
||||
v-text="line"
|
||||
/>
|
||||
<progress
|
||||
v-if="progress"
|
||||
class="progress is-dark"
|
||||
max="1"
|
||||
:value="progress"
|
||||
/>
|
||||
</div>
|
||||
<div class="media-right">
|
||||
<a @click.prevent.stop="openDetails">
|
||||
<mdicon class="icon has-text-grey" name="dots-vertical" size="16" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ControlImage from '@/components/ControlImage.vue'
|
||||
|
||||
export default {
|
||||
name: 'ListItem',
|
||||
components: { ControlImage },
|
||||
props: {
|
||||
icon: { default: null, type: String },
|
||||
image: { default: null, type: String },
|
||||
index: { default: null, type: [String, Number] },
|
||||
isItem: { default: true, type: Boolean },
|
||||
lines: { default: null, type: Array },
|
||||
progress: { default: null, type: Number }
|
||||
},
|
||||
emits: ['open', 'openDetails'],
|
||||
methods: {
|
||||
open() {
|
||||
this.$emit('open')
|
||||
},
|
||||
openDetails() {
|
||||
this.$emit('openDetails')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.progress {
|
||||
height: 0.25rem;
|
||||
}
|
||||
|
||||
.media.with-progress {
|
||||
margin-top: 0.375rem;
|
||||
}
|
||||
</style>
|
@ -52,7 +52,7 @@ import webapi from '@/webapi'
|
||||
export default {
|
||||
name: 'ListItemQueueItem',
|
||||
props: {
|
||||
current_position: { required: true, type: Number },
|
||||
currentPosition: { required: true, type: Number },
|
||||
editing: Boolean,
|
||||
item: { required: true, type: Object },
|
||||
position: { required: true, type: Number },
|
||||
@ -66,7 +66,7 @@ export default {
|
||||
return this.item.id === this.playerStore.item_id
|
||||
},
|
||||
isNext() {
|
||||
return this.current_position < 0 || this.position >= this.current_position
|
||||
return this.currentPosition < 0 || this.position >= this.currentPosition
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
@ -1,41 +1,32 @@
|
||||
<template>
|
||||
<template v-for="item in items" :key="item.itemId">
|
||||
<div
|
||||
class="media is-align-items-center is-clickable mb-0"
|
||||
@click="open(item.item)"
|
||||
>
|
||||
<mdicon class="media-left icon" :name="icon(item.item)" />
|
||||
<div class="media-content">
|
||||
<p class="is-size-6 has-text-weight-bold" v-text="item.item.name" />
|
||||
</div>
|
||||
<div class="media-right">
|
||||
<a @click.prevent.stop="openDialog(item.item)">
|
||||
<mdicon class="icon has-text-grey" name="dots-vertical" size="16" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<teleport to="#app">
|
||||
<modal-dialog-playlist
|
||||
:item="selectedItem"
|
||||
:show="showDetailsModal"
|
||||
@close="showDetailsModal = false"
|
||||
/>
|
||||
</teleport>
|
||||
<list-item
|
||||
v-for="item in items"
|
||||
:key="item.itemId"
|
||||
:icon="icon(item.item)"
|
||||
:is-item="item.isItem"
|
||||
:index="item.index"
|
||||
:lines="[item.item.name]"
|
||||
@open="open(item.item)"
|
||||
@open-details="openDetails(item.item)"
|
||||
/>
|
||||
<modal-dialog-playlist
|
||||
:item="selectedItem"
|
||||
:show="showDetailsModal"
|
||||
@close="showDetailsModal = false"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ListItem from '@/components/ListItem.vue'
|
||||
import ModalDialogPlaylist from '@/components/ModalDialogPlaylist.vue'
|
||||
|
||||
export default {
|
||||
name: 'ListPlaylists',
|
||||
components: { ModalDialogPlaylist },
|
||||
components: { ListItem, ModalDialogPlaylist },
|
||||
props: { items: { required: true, type: Object } },
|
||||
|
||||
data() {
|
||||
return { selectedItem: {}, showDetailsModal: false }
|
||||
},
|
||||
|
||||
methods: {
|
||||
icon(item) {
|
||||
if (item.type === 'folder') {
|
||||
@ -52,7 +43,7 @@ export default {
|
||||
this.$router.push({ name: 'playlist', params: { id: item.id } })
|
||||
}
|
||||
},
|
||||
openDialog(item) {
|
||||
openDetails(item) {
|
||||
this.selectedItem = item
|
||||
this.showDetailsModal = true
|
||||
}
|
||||
|
@ -1,40 +1,27 @@
|
||||
<template>
|
||||
<template v-for="item in items" :key="item.id">
|
||||
<div
|
||||
class="media is-align-items-center is-clickable mb-0"
|
||||
@click="open(item)"
|
||||
>
|
||||
<div class="media-content">
|
||||
<div class="is-size-6 has-text-weight-bold" v-text="item.name" />
|
||||
<div
|
||||
class="is-size-7 has-text-weight-bold has-text-grey"
|
||||
v-text="item.owner.display_name"
|
||||
/>
|
||||
</div>
|
||||
<div class="media-right">
|
||||
<a @click.prevent.stop="openDialog(item)">
|
||||
<mdicon class="icon has-text-grey" name="dots-vertical" size="16" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<teleport to="#app">
|
||||
<modal-dialog-playlist-spotify
|
||||
:item="selectedItem"
|
||||
:show="showDetailsModal"
|
||||
@close="showDetailsModal = false"
|
||||
/>
|
||||
</teleport>
|
||||
<list-item
|
||||
v-for="item in items"
|
||||
:key="item.id"
|
||||
:is-item="item.isItem"
|
||||
:index="item.index"
|
||||
:lines="[item.name, item.owner.display_name]"
|
||||
@open="open(item)"
|
||||
@open-details="openDetails(item)"
|
||||
/>
|
||||
<modal-dialog-playlist-spotify
|
||||
:item="selectedItem"
|
||||
:show="showDetailsModal"
|
||||
@close="showDetailsModal = false"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ListItem from '@/components/ListItem.vue'
|
||||
import ModalDialogPlaylistSpotify from '@/components/ModalDialogPlaylistSpotify.vue'
|
||||
|
||||
export default {
|
||||
name: 'ListPlaylistsSpotify',
|
||||
components: {
|
||||
ModalDialogPlaylistSpotify
|
||||
},
|
||||
components: { ListItem, ModalDialogPlaylistSpotify },
|
||||
props: { items: { required: true, type: Object } },
|
||||
|
||||
data() {
|
||||
@ -45,7 +32,7 @@ export default {
|
||||
open(item) {
|
||||
this.$router.push({ name: 'playlist-spotify', params: { id: item.id } })
|
||||
},
|
||||
openDialog(item) {
|
||||
openDetails(item) {
|
||||
this.selectedItem = item
|
||||
this.showDetailsModal = true
|
||||
}
|
||||
|
@ -1,73 +1,36 @@
|
||||
<template>
|
||||
<template v-for="item in items" :key="item.itemId">
|
||||
<div v-if="!item.isItem" class="py-5">
|
||||
<span
|
||||
:id="`index_${item.index}`"
|
||||
class="tag is-small has-text-weight-bold"
|
||||
v-text="item.index"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-else
|
||||
class="media is-align-items-center is-clickable mb-0"
|
||||
:class="{ 'with-progress': showProgress }"
|
||||
@click="play(item.item)"
|
||||
>
|
||||
<mdicon
|
||||
v-if="showIcon"
|
||||
class="media-left icon"
|
||||
name="file-music-outline"
|
||||
/>
|
||||
<div class="media-content">
|
||||
<div
|
||||
class="is-size-6 has-text-weight-bold"
|
||||
:class="{
|
||||
'has-text-grey':
|
||||
item.item.media_kind === 'podcast' && item.item.play_count > 0
|
||||
}"
|
||||
v-text="item.item.title"
|
||||
/>
|
||||
<div
|
||||
class="is-size-7 has-text-weight-bold has-text-grey"
|
||||
v-text="item.item.artist"
|
||||
/>
|
||||
<div class="is-size-7 has-text-grey" v-text="item.item.album" />
|
||||
<progress
|
||||
v-if="showProgress && item.item.seek_ms > 0"
|
||||
class="progress is-dark"
|
||||
:max="item.item.length_ms"
|
||||
:value="item.item.seek_ms"
|
||||
/>
|
||||
</div>
|
||||
<div class="media-right">
|
||||
<a @click.prevent.stop="openDialog(item.item)">
|
||||
<mdicon class="icon has-text-grey" name="dots-vertical" size="16" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<teleport to="#app">
|
||||
<modal-dialog-track
|
||||
:item="selectedItem"
|
||||
:show="showDetailsModal"
|
||||
@close="showDetailsModal = false"
|
||||
@play-count-changed="$emit('play-count-changed')"
|
||||
/>
|
||||
</teleport>
|
||||
<list-item
|
||||
v-for="item in items"
|
||||
:key="item.itemId"
|
||||
:icon="icon"
|
||||
:is-item="item.isItem"
|
||||
:index="item.index"
|
||||
:lines="[item.item.title, item.item.artist, item.item.album]"
|
||||
:progress="progress(item.item)"
|
||||
@open="open(item.item)"
|
||||
@open-details="openDetails(item.item)"
|
||||
/>
|
||||
<modal-dialog-track
|
||||
:item="selectedItem"
|
||||
:show="showDetailsModal"
|
||||
@close="showDetailsModal = false"
|
||||
@play-count-changed="$emit('play-count-changed')"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ListItem from '@/components/ListItem.vue'
|
||||
import ModalDialogTrack from '@/components/ModalDialogTrack.vue'
|
||||
import webapi from '@/webapi'
|
||||
|
||||
export default {
|
||||
name: 'ListTracks',
|
||||
components: { ModalDialogTrack },
|
||||
components: { ListItem, ModalDialogTrack },
|
||||
props: {
|
||||
expression: { default: '', type: String },
|
||||
items: { required: true, type: Object },
|
||||
showIcon: Boolean,
|
||||
showProgress: Boolean,
|
||||
items: { default: null, type: Object },
|
||||
icon: { default: null, type: String },
|
||||
showProgress: { default: false, type: Boolean },
|
||||
uris: { default: '', type: String }
|
||||
},
|
||||
emits: ['play-count-changed'],
|
||||
@ -75,11 +38,7 @@ export default {
|
||||
return { selectedItem: {}, showDetailsModal: false }
|
||||
},
|
||||
methods: {
|
||||
openDialog(item) {
|
||||
this.selectedItem = item
|
||||
this.showDetailsModal = true
|
||||
},
|
||||
play(item) {
|
||||
open(item) {
|
||||
if (this.uris) {
|
||||
webapi.player_play_uri(this.uris, false, this.items.items.indexOf(item))
|
||||
} else if (this.expression) {
|
||||
@ -91,17 +50,20 @@ export default {
|
||||
} else {
|
||||
webapi.player_play_uri(item.uri, false)
|
||||
}
|
||||
},
|
||||
openDetails(item) {
|
||||
this.selectedItem = item
|
||||
this.showDetailsModal = true
|
||||
},
|
||||
// 'has-text-grey': item.item.media_kind === 'podcast' && item.item.play_count > 0
|
||||
progress(item) {
|
||||
if (item.item) {
|
||||
if (this.showProgress && item.item.seek_ms > 0) {
|
||||
return item.item.seek_ms / item.item.length_ms
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.progress {
|
||||
height: 0.25rem;
|
||||
}
|
||||
|
||||
.media.with-progress {
|
||||
margin-top: 0.375rem;
|
||||
}
|
||||
</style>
|
||||
|
@ -36,19 +36,17 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="media-right">
|
||||
<a @click.prevent.stop="openDialog(item)">
|
||||
<a @click.prevent.stop="openDetails(item)">
|
||||
<mdicon class="icon has-text-grey" name="dots-vertical" size="16" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<teleport to="#app">
|
||||
<modal-dialog-track-spotify
|
||||
:item="selectedItem"
|
||||
:show="showDetailsModal"
|
||||
@close="showDetailsModal = false"
|
||||
/>
|
||||
</teleport>
|
||||
<modal-dialog-track-spotify
|
||||
:item="selectedItem"
|
||||
:show="showDetailsModal"
|
||||
@close="showDetailsModal = false"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
@ -66,7 +64,7 @@ export default {
|
||||
return { selectedItem: {}, showDetailsModal: false }
|
||||
},
|
||||
methods: {
|
||||
openDialog(item) {
|
||||
openDetails(item) {
|
||||
this.selectedItem = item
|
||||
this.showDetailsModal = true
|
||||
},
|
||||
|
@ -4,12 +4,12 @@
|
||||
class="lyrics"
|
||||
@touchstart="autoScrolling = false"
|
||||
@touchend="autoScrolling = true"
|
||||
@scroll.passive="start_scrolling"
|
||||
@wheel.passive="start_scrolling"
|
||||
@scroll.passive="startScrolling"
|
||||
@wheel.passive="startScrolling"
|
||||
>
|
||||
<template v-for="(verse, index) in lyrics" :key="index">
|
||||
<div
|
||||
v-if="index === verse_index"
|
||||
v-if="index === verseIndex"
|
||||
:class="{ 'is-highlighted': playerStore.isPlaying }"
|
||||
>
|
||||
<span
|
||||
@ -85,7 +85,7 @@ export default {
|
||||
}
|
||||
return parsed
|
||||
},
|
||||
verse_index() {
|
||||
verseIndex() {
|
||||
if (this.lyrics.length && this.lyrics[0].time) {
|
||||
const currentTime = this.playerStore.item_progress_ms / 1000,
|
||||
la = this.lyrics,
|
||||
@ -96,7 +96,7 @@ export default {
|
||||
la[this.lastIndex].time > currentTime
|
||||
// Reset the cache when the track has changed or has been seeked
|
||||
if (trackChanged || trackSeeked) {
|
||||
this.reset_scrolling()
|
||||
this.resetScrolling()
|
||||
}
|
||||
// Check the next two items and the last one before searching
|
||||
if (
|
||||
@ -134,20 +134,20 @@ export default {
|
||||
}
|
||||
return index
|
||||
}
|
||||
this.reset_scrolling()
|
||||
this.resetScrolling()
|
||||
return -1
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
verse_index() {
|
||||
verseIndex() {
|
||||
if (this.autoScrolling) {
|
||||
this.scroll_to_verse()
|
||||
this.scrollToVerse()
|
||||
}
|
||||
this.lastIndex = this.verse_index
|
||||
this.lastIndex = this.verseIndex
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
reset_scrolling() {
|
||||
resetScrolling() {
|
||||
// Scroll to the start of the lyrics in all cases
|
||||
if (this.playerStore.item_id !== this.lastItemId && this.$refs.lyrics) {
|
||||
this.$refs.lyrics.scrollTo(0, 0)
|
||||
@ -155,13 +155,13 @@ export default {
|
||||
this.lastItemId = this.playerStore.item_id
|
||||
this.lastIndex = -1
|
||||
},
|
||||
scroll_to_verse() {
|
||||
scrollToVerse() {
|
||||
const pane = this.$refs.lyrics
|
||||
if (this.verse_index === -1) {
|
||||
if (this.verseIndex === -1) {
|
||||
pane.scrollTo(0, 0)
|
||||
return
|
||||
}
|
||||
const currentVerse = pane.children[this.verse_index]
|
||||
const currentVerse = pane.children[this.verseIndex]
|
||||
pane.scrollBy({
|
||||
behavior: 'smooth',
|
||||
left: 0,
|
||||
@ -172,7 +172,7 @@ export default {
|
||||
pane.scrollTop
|
||||
})
|
||||
},
|
||||
start_scrolling(event) {
|
||||
startScrolling(event) {
|
||||
// Consider only user events
|
||||
if (event.screenX ?? event.screenY) {
|
||||
this.autoScrolling = false
|
||||
|
@ -11,14 +11,14 @@
|
||||
<p class="control has-icons-left">
|
||||
<input
|
||||
ref="playlist_name_field"
|
||||
v-model="playlist_name"
|
||||
v-model="playlistName"
|
||||
class="input"
|
||||
type="text"
|
||||
pattern=".+"
|
||||
required
|
||||
:placeholder="$t('dialog.playlist.save.playlist-name')"
|
||||
:disabled="loading"
|
||||
@input="check_name"
|
||||
@input="check"
|
||||
/>
|
||||
<mdicon class="icon is-left" name="playlist-music" size="16" />
|
||||
</p>
|
||||
@ -41,7 +41,7 @@ export default {
|
||||
return {
|
||||
disabled: true,
|
||||
loading: false,
|
||||
playlist_name: ''
|
||||
playlistName: ''
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@ -75,17 +75,17 @@ export default {
|
||||
cancel() {
|
||||
this.$emit('close')
|
||||
},
|
||||
check_name(event) {
|
||||
check(event) {
|
||||
const { validity } = event.target
|
||||
this.disabled = validity.patternMismatch || validity.valueMissing
|
||||
},
|
||||
save() {
|
||||
this.loading = true
|
||||
webapi
|
||||
.queue_save_playlist(this.playlist_name)
|
||||
.queue_save_playlist(this.playlistName)
|
||||
.then(() => {
|
||||
this.$emit('close')
|
||||
this.playlist_name = ''
|
||||
this.playlistName = ''
|
||||
})
|
||||
.catch(() => {
|
||||
this.loading = false
|
||||
|
@ -23,7 +23,7 @@ export default {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
spotify_track: {}
|
||||
spotifyTrack: {}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@ -89,10 +89,10 @@ export default {
|
||||
spotifyApi
|
||||
.getTrack(this.item.path.slice(this.item.path.lastIndexOf(':') + 1))
|
||||
.then((response) => {
|
||||
this.spotify_track = response
|
||||
this.spotifyTrack = response
|
||||
})
|
||||
} else {
|
||||
this.spotify_track = {}
|
||||
this.spotifyTrack = {}
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -102,7 +102,7 @@ export default {
|
||||
if (this.item.data_kind === 'spotify') {
|
||||
this.$router.push({
|
||||
name: 'music-spotify-album',
|
||||
params: { id: this.spotify_track.album.id }
|
||||
params: { id: this.spotifyTrack.album.id }
|
||||
})
|
||||
} else if (this.item.media_kind === 'podcast') {
|
||||
this.$router.push({
|
||||
@ -126,7 +126,7 @@ export default {
|
||||
if (this.item.data_kind === 'spotify') {
|
||||
this.$router.push({
|
||||
name: 'music-spotify-artist',
|
||||
params: { id: this.spotify_track.artists[0].id }
|
||||
params: { id: this.spotifyTrack.artists[0].id }
|
||||
})
|
||||
} else if (
|
||||
this.item.media_kind === 'music' ||
|
||||
|
@ -31,7 +31,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<control-switch v-model="rescan_metadata">
|
||||
<control-switch v-model="rescanMetadata">
|
||||
<template #label>
|
||||
<span v-text="$t('dialog.update.rescan-metadata')" />
|
||||
</template>
|
||||
@ -64,7 +64,7 @@ export default {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
rescan_metadata: false
|
||||
rescanMetadata: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@ -87,7 +87,7 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
analyse() {
|
||||
if (this.rescan_metadata) {
|
||||
if (this.rescanMetadata) {
|
||||
webapi.library_rescan(this.libraryStore.update_dialog_scan_kind)
|
||||
} else {
|
||||
webapi.library_update(this.libraryStore.update_dialog_scan_kind)
|
||||
|
@ -107,6 +107,12 @@ export default {
|
||||
show: true,
|
||||
sub: true
|
||||
},
|
||||
{
|
||||
key: 'navigation.composers',
|
||||
name: 'music-composers',
|
||||
show: true,
|
||||
sub: true
|
||||
},
|
||||
{
|
||||
key: 'navigation.spotify',
|
||||
name: 'music-spotify',
|
||||
|
@ -1,14 +1,17 @@
|
||||
<template>
|
||||
<section v-if="notifications.length > 0" class="notifications">
|
||||
<section v-if="!notificationsStore.isEmpty" class="notifications">
|
||||
<div class="columns is-centered">
|
||||
<div class="column is-half">
|
||||
<div
|
||||
v-for="notification in notifications"
|
||||
v-for="notification in notificationsStore.list"
|
||||
:key="notification.id"
|
||||
class="notification"
|
||||
:class="notification.type ? `is-${notification.type}` : ''"
|
||||
>
|
||||
<button class="delete" @click="remove(notification)" />
|
||||
<button
|
||||
class="delete"
|
||||
@click="notificationsStore.remove(notification)"
|
||||
/>
|
||||
<div class="text" v-text="notification.text" />
|
||||
</div>
|
||||
</div>
|
||||
@ -21,21 +24,8 @@ import { useNotificationsStore } from '@/stores/notifications'
|
||||
|
||||
export default {
|
||||
name: 'NotificationList',
|
||||
|
||||
setup() {
|
||||
return { notificationsStore: useNotificationsStore() }
|
||||
},
|
||||
|
||||
computed: {
|
||||
notifications() {
|
||||
return this.notificationsStore.list
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
remove(notification) {
|
||||
this.notificationsStore.remove(notification)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
@ -20,7 +20,8 @@
|
||||
"save": "Speichern",
|
||||
"send": "Senden",
|
||||
"show-more": "Zeige mehr",
|
||||
"shuffle": "Zufallswiedergabe"
|
||||
"shuffle": "Zufallswiedergabe",
|
||||
"update": "Neu einlesen"
|
||||
},
|
||||
"count": {
|
||||
"albums": "{count} Album|{count} Album|{count} Alben",
|
||||
@ -116,6 +117,7 @@
|
||||
"albums": "Alben",
|
||||
"artists": "Künstler",
|
||||
"audiobooks": "Hörbücher",
|
||||
"composers": "Komponisten",
|
||||
"now-playing": " - {album}",
|
||||
"stream-error": "HTTP-stream-Fehler: Stream kann nicht geladen werden oder wurde wg. Netzwerkfehler gestopt",
|
||||
"stream": "HTTP-stream",
|
||||
@ -216,8 +218,7 @@
|
||||
},
|
||||
"podcasts": {
|
||||
"new-episodes": "Neue Episoden",
|
||||
"title": "Podcasts",
|
||||
"update": "Neu einlesen"
|
||||
"title": "Podcasts"
|
||||
},
|
||||
"queue": {
|
||||
"title": "Warteschlange"
|
||||
|
@ -20,7 +20,8 @@
|
||||
"save": "Save",
|
||||
"send": "Send",
|
||||
"show-more": "Show more",
|
||||
"shuffle": "Shuffle"
|
||||
"shuffle": "Shuffle",
|
||||
"update": "Update"
|
||||
},
|
||||
"count": {
|
||||
"albums": "{count} album|{count} album|{count} albums",
|
||||
@ -116,6 +117,7 @@
|
||||
"albums": "Albums",
|
||||
"artists": "Artists",
|
||||
"audiobooks": "Audiobooks",
|
||||
"composers": "Composers",
|
||||
"now-playing": " - {album}",
|
||||
"stream-error": "HTTP stream error: failed to load stream or stopped loading due to network problem",
|
||||
"stream": "HTTP stream",
|
||||
@ -216,8 +218,7 @@
|
||||
},
|
||||
"podcasts": {
|
||||
"new-episodes": "New Episodes",
|
||||
"title": "Podcasts",
|
||||
"update": "Update"
|
||||
"title": "Podcasts"
|
||||
},
|
||||
"queue": {
|
||||
"title": "Queue"
|
||||
|
@ -20,7 +20,8 @@
|
||||
"save": "Enregistrer",
|
||||
"send": "Envoyer",
|
||||
"show-more": "Afficher plus",
|
||||
"shuffle": "Lecture aléatoire"
|
||||
"shuffle": "Lecture aléatoire",
|
||||
"update": "Actualiser"
|
||||
},
|
||||
"count": {
|
||||
"albums": "{count} album|{count} album|{count} albums",
|
||||
@ -116,6 +117,7 @@
|
||||
"albums": "Albums",
|
||||
"artists": "Artistes",
|
||||
"audiobooks": "Livres audio",
|
||||
"composers": "Compositeurs",
|
||||
"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",
|
||||
@ -216,8 +218,7 @@
|
||||
},
|
||||
"podcasts": {
|
||||
"new-episodes": "Nouveaux épisodes",
|
||||
"title": "Podcasts",
|
||||
"update": "Actualiser"
|
||||
"title": "Podcasts"
|
||||
},
|
||||
"queue": {
|
||||
"title": "File d’attente"
|
||||
|
@ -20,7 +20,8 @@
|
||||
"save": "保存",
|
||||
"send": "发送",
|
||||
"show-more": "显示更多",
|
||||
"shuffle": "随机播放"
|
||||
"shuffle": "随机播放",
|
||||
"update": "更新"
|
||||
},
|
||||
"count": {
|
||||
"albums": "{count} 张专辑|{count} 张专辑",
|
||||
@ -116,6 +117,7 @@
|
||||
"albums": "专辑",
|
||||
"artists": "艺人",
|
||||
"audiobooks": "有声读物",
|
||||
"composers": "作曲家",
|
||||
"now-playing": " - {album}",
|
||||
"stream-error": "HTTP流错误:流载入失败或者由于网络原因无法载入",
|
||||
"stream": "HTTP流",
|
||||
@ -216,8 +218,7 @@
|
||||
},
|
||||
"podcasts": {
|
||||
"new-episodes": "最新单集",
|
||||
"title": "播客",
|
||||
"update": "更新"
|
||||
"title": "播客"
|
||||
},
|
||||
"queue": {
|
||||
"title": "清单"
|
||||
|
@ -20,7 +20,8 @@
|
||||
"save": "儲存",
|
||||
"send": "發送",
|
||||
"show-more": "顯示更多",
|
||||
"shuffle": "隨機播放"
|
||||
"shuffle": "隨機播放",
|
||||
"update": "更新"
|
||||
},
|
||||
"count": {
|
||||
"albums": "{count} 張專輯|{count} 張專輯",
|
||||
@ -116,6 +117,7 @@
|
||||
"albums": "專輯",
|
||||
"artists": "藝人",
|
||||
"audiobooks": "有聲書",
|
||||
"composers": "作曲家",
|
||||
"now-playing": " - {album}",
|
||||
"stream-error": "HTTP串流錯誤:串流載入失敗或者由於網絡原因無法載入",
|
||||
"stream": "HTTP串流",
|
||||
@ -216,8 +218,7 @@
|
||||
},
|
||||
"podcasts": {
|
||||
"new-episodes": "最新單集",
|
||||
"title": "Podcast",
|
||||
"update": "更新"
|
||||
"title": "Podcast"
|
||||
},
|
||||
"queue": {
|
||||
"title": "清單"
|
||||
|
@ -34,8 +34,6 @@
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #footer>
|
||||
<div
|
||||
class="is-size-7 mt-6"
|
||||
v-text="
|
||||
|
@ -15,7 +15,7 @@
|
||||
:button="{ handler: play, icon: 'shuffle', key: 'actions.shuffle' }"
|
||||
/>
|
||||
<control-button
|
||||
:button="{ handler: showDetails, icon: 'dots-horizontal' }"
|
||||
:button="{ handler: openDetails, icon: 'dots-horizontal' }"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
@ -25,7 +25,7 @@
|
||||
:artist="album.artist"
|
||||
:album="album.name"
|
||||
class="is-clickable is-medium"
|
||||
@click="showDetails"
|
||||
@click="openDetails"
|
||||
/>
|
||||
</template>
|
||||
<template #content>
|
||||
@ -98,11 +98,11 @@ export default {
|
||||
params: { id: this.album.artist_id }
|
||||
})
|
||||
},
|
||||
openDetails() {
|
||||
this.showDetailsModal = true
|
||||
},
|
||||
play() {
|
||||
webapi.player_play_uri(this.album.uri, true)
|
||||
},
|
||||
showDetails() {
|
||||
this.showDetailsModal = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,7 @@
|
||||
:button="{ handler: play, icon: 'shuffle', key: 'actions.shuffle' }"
|
||||
/>
|
||||
<control-button
|
||||
:button="{ handler: showDetails, icon: 'dots-horizontal' }"
|
||||
:button="{ handler: openDetails, icon: 'dots-horizontal' }"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
@ -25,7 +25,7 @@
|
||||
:artist="album.artists[0].name"
|
||||
:album="album.name"
|
||||
class="is-clickable is-medium"
|
||||
@click="showDetails"
|
||||
@click="openDetails"
|
||||
/>
|
||||
</template>
|
||||
<template #content>
|
||||
@ -102,12 +102,12 @@ export default {
|
||||
params: { id: this.album.artists[0].id }
|
||||
})
|
||||
},
|
||||
openDetails() {
|
||||
this.showDetailsModal = true
|
||||
},
|
||||
play() {
|
||||
this.showDetailsModal = false
|
||||
webapi.player_play_uri(this.album.uri, true)
|
||||
},
|
||||
showDetails() {
|
||||
this.showDetailsModal = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -36,7 +36,7 @@
|
||||
v-text="$t('options.sort.title')"
|
||||
/>
|
||||
<control-dropdown
|
||||
v-model:value="uiStore.albums_sort"
|
||||
v-model:value="uiStore.albumsSort"
|
||||
:options="groupings"
|
||||
/>
|
||||
</div>
|
||||
@ -101,7 +101,7 @@ export default {
|
||||
computed: {
|
||||
albums() {
|
||||
const { options } = this.groupings.find(
|
||||
(grouping) => grouping.id === this.uiStore.albums_sort
|
||||
(grouping) => grouping.id === this.uiStore.albumsSort
|
||||
)
|
||||
options.filters = [
|
||||
(album) => !this.uiStore.hideSingles || album.track_count > 2,
|
||||
|
@ -26,7 +26,7 @@
|
||||
v-text="$t('page.artist.sort.title')"
|
||||
/>
|
||||
<control-dropdown
|
||||
v-model:value="uiStore.artist_albums_sort"
|
||||
v-model:value="uiStore.artistAlbumsSort"
|
||||
:options="groupings"
|
||||
/>
|
||||
</div>
|
||||
@ -37,7 +37,7 @@
|
||||
</template>
|
||||
<template #heading-right>
|
||||
<control-button
|
||||
:button="{ handler: showDetails, icon: 'dots-horizontal' }"
|
||||
:button="{ handler: openDetails, icon: 'dots-horizontal' }"
|
||||
/>
|
||||
<control-button
|
||||
:button="{ handler: play, icon: 'shuffle', key: 'actions.shuffle' }"
|
||||
@ -110,7 +110,7 @@ export default {
|
||||
computed: {
|
||||
albums() {
|
||||
const { options } = this.groupings.find(
|
||||
(grouping) => grouping.id === this.uiStore.artist_albums_sort
|
||||
(grouping) => grouping.id === this.uiStore.artistAlbumsSort
|
||||
)
|
||||
options.filters = [
|
||||
(album) => !this.uiStore.hideSpotify || album.data_kind !== 'spotify'
|
||||
@ -153,6 +153,9 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
openDetails() {
|
||||
this.showDetailsModal = true
|
||||
},
|
||||
openTracks() {
|
||||
this.$router.push({
|
||||
name: 'music-artist-tracks',
|
||||
@ -164,9 +167,6 @@ export default {
|
||||
this.albums.items.map((item) => item.uri).join(),
|
||||
true
|
||||
)
|
||||
},
|
||||
showDetails() {
|
||||
this.showDetailsModal = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@
|
||||
</template>
|
||||
<template #heading-right>
|
||||
<control-button
|
||||
:button="{ handler: showDetails, icon: 'dots-horizontal' }"
|
||||
:button="{ handler: openDetails, icon: 'dots-horizontal' }"
|
||||
/>
|
||||
<control-button
|
||||
:button="{ handler: play, icon: 'shuffle', key: 'actions.shuffle' }"
|
||||
@ -106,7 +106,7 @@ export default {
|
||||
heading() {
|
||||
return {
|
||||
subtitle: [{ count: this.total, key: 'count.albums' }],
|
||||
title: this.$t('artist.name')
|
||||
title: this.artist.name
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -130,12 +130,12 @@ export default {
|
||||
loaded(data.items.length, PAGE_SIZE)
|
||||
})
|
||||
},
|
||||
openDetails() {
|
||||
this.showDetailsModal = true
|
||||
},
|
||||
play() {
|
||||
this.showDetailsModal = false
|
||||
webapi.player_play_uri(this.artist.uri, true)
|
||||
},
|
||||
showDetails() {
|
||||
this.showDetailsModal = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -27,7 +27,7 @@
|
||||
v-text="$t('options.sort.title')"
|
||||
/>
|
||||
<control-dropdown
|
||||
v-model:value="uiStore.artist_tracks_sort"
|
||||
v-model:value="uiStore.artistTracksSort"
|
||||
:options="groupings"
|
||||
/>
|
||||
</div>
|
||||
@ -38,14 +38,14 @@
|
||||
</template>
|
||||
<template #heading-right>
|
||||
<control-button
|
||||
:button="{ handler: showDetails, icon: 'dots-horizontal' }"
|
||||
:button="{ handler: openDetails, icon: 'dots-horizontal' }"
|
||||
/>
|
||||
<control-button
|
||||
:button="{ handler: play, icon: 'shuffle', key: 'actions.shuffle' }"
|
||||
/>
|
||||
</template>
|
||||
<template #content>
|
||||
<list-tracks :items="tracks" :uris="track_uris" />
|
||||
<list-tracks :items="tracks" :uris="trackUris" />
|
||||
<modal-dialog-artist
|
||||
:item="artist"
|
||||
:show="showDetailsModal"
|
||||
@ -111,7 +111,7 @@ export default {
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
album_count() {
|
||||
albumCount() {
|
||||
return new Set(
|
||||
[...this.tracks]
|
||||
.filter((track) => track.isItem)
|
||||
@ -139,7 +139,7 @@ export default {
|
||||
return {
|
||||
subtitle: [
|
||||
{
|
||||
count: this.album_count,
|
||||
count: this.albumCount,
|
||||
handler: this.openArtist,
|
||||
key: 'count.albums'
|
||||
},
|
||||
@ -148,12 +148,12 @@ export default {
|
||||
title: this.artist.name
|
||||
}
|
||||
},
|
||||
track_uris() {
|
||||
trackUris() {
|
||||
return this.trackList.items.map((item) => item.uri).join()
|
||||
},
|
||||
tracks() {
|
||||
const { options } = this.groupings.find(
|
||||
(grouping) => grouping.id === this.uiStore.artist_tracks_sort
|
||||
(grouping) => grouping.id === this.uiStore.artistTracksSort
|
||||
)
|
||||
options.filters = [
|
||||
(track) => !this.uiStore.hideSpotify || track.data_kind !== 'spotify'
|
||||
@ -169,14 +169,14 @@ export default {
|
||||
params: { id: this.artist.id }
|
||||
})
|
||||
},
|
||||
openDetails() {
|
||||
this.showDetailsModal = true
|
||||
},
|
||||
play() {
|
||||
webapi.player_play_uri(
|
||||
this.trackList.items.map((item) => item.uri).join(),
|
||||
true
|
||||
)
|
||||
},
|
||||
showDetails() {
|
||||
this.showDetailsModal = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -35,7 +35,7 @@
|
||||
v-text="$t('options.sort.title')"
|
||||
/>
|
||||
<control-dropdown
|
||||
v-model:value="uiStore.artists_sort"
|
||||
v-model:value="uiStore.artistsSort"
|
||||
:options="groupings"
|
||||
/>
|
||||
</div>
|
||||
@ -100,7 +100,7 @@ export default {
|
||||
computed: {
|
||||
artists() {
|
||||
const { options } = this.groupings.find(
|
||||
(grouping) => grouping.id === this.uiStore.artists_sort
|
||||
(grouping) => grouping.id === this.uiStore.artistsSort
|
||||
)
|
||||
options.filters = [
|
||||
(artist) =>
|
||||
|
@ -19,7 +19,7 @@
|
||||
}"
|
||||
/>
|
||||
<control-button
|
||||
:button="{ handler: showDetails, icon: 'dots-horizontal' }"
|
||||
:button="{ handler: openDetails, icon: 'dots-horizontal' }"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
@ -29,7 +29,7 @@
|
||||
:artist="album.artist"
|
||||
:album="album.name"
|
||||
class="is-clickable is-medium"
|
||||
@click="showDetails"
|
||||
@click="openDetails"
|
||||
/>
|
||||
</template>
|
||||
<template #content>
|
||||
@ -96,11 +96,11 @@ export default {
|
||||
params: { id: this.album.artist_id }
|
||||
})
|
||||
},
|
||||
openDetails() {
|
||||
this.showDetailsModal = true
|
||||
},
|
||||
play() {
|
||||
webapi.player_play_uri(this.album.uri, false)
|
||||
},
|
||||
showDetails() {
|
||||
this.showDetailsModal = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,14 +6,10 @@
|
||||
</template>
|
||||
<template #heading-right>
|
||||
<control-button
|
||||
:button="{ handler: showDetails, icon: 'dots-horizontal' }"
|
||||
:button="{ handler: openDetails, icon: 'dots-horizontal' }"
|
||||
/>
|
||||
<control-button
|
||||
:button="{
|
||||
handler: play,
|
||||
icon: 'play',
|
||||
key: 'page.audiobooks.artist.play'
|
||||
}"
|
||||
:button="{ handler: play, icon: 'play', key: 'actions.play' }"
|
||||
/>
|
||||
</template>
|
||||
<template #content>
|
||||
@ -85,14 +81,14 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
openDetails() {
|
||||
this.showDetailsModal = true
|
||||
},
|
||||
play() {
|
||||
webapi.player_play_uri(
|
||||
this.albums.items.map((item) => item.uri).join(),
|
||||
false
|
||||
)
|
||||
},
|
||||
showDetails() {
|
||||
this.showDetailsModal = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@
|
||||
</template>
|
||||
<template #heading-right>
|
||||
<control-button
|
||||
:button="{ handler: showDetails, icon: 'dots-horizontal' }"
|
||||
:button="{ handler: openDetails, icon: 'dots-horizontal' }"
|
||||
/>
|
||||
<control-button
|
||||
:button="{ handler: play, icon: 'shuffle', key: 'actions.shuffle' }"
|
||||
@ -89,6 +89,9 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
openDetails() {
|
||||
this.showDetailsModal = true
|
||||
},
|
||||
openTracks() {
|
||||
this.$router.push({
|
||||
name: 'music-composer-tracks',
|
||||
@ -97,9 +100,6 @@ export default {
|
||||
},
|
||||
play() {
|
||||
webapi.player_play_expression(this.expression, true)
|
||||
},
|
||||
showDetails() {
|
||||
this.showDetailsModal = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,7 @@
|
||||
v-text="$t('options.sort.title')"
|
||||
/>
|
||||
<control-dropdown
|
||||
v-model:value="uiStore.composer_tracks_sort"
|
||||
v-model:value="uiStore.composerTracksSort"
|
||||
:options="groupings"
|
||||
/>
|
||||
</div>
|
||||
@ -21,7 +21,7 @@
|
||||
</template>
|
||||
<template #heading-right>
|
||||
<control-button
|
||||
:button="{ handler: showDetails, icon: 'dots-horizontal' }"
|
||||
:button="{ handler: openDetails, icon: 'dots-horizontal' }"
|
||||
/>
|
||||
<control-button
|
||||
:button="{ handler: play, icon: 'shuffle', key: 'actions.shuffle' }"
|
||||
@ -129,9 +129,9 @@ export default {
|
||||
},
|
||||
tracks() {
|
||||
const { options } = this.groupings.find(
|
||||
(grouping) => grouping.id === this.uiStore.composer_tracks_sort
|
||||
(grouping) => grouping.id === this.uiStore.composerTracksSort
|
||||
)
|
||||
return this.tracks_list.group(options)
|
||||
return this.trackList.group(options)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@ -141,11 +141,11 @@ export default {
|
||||
params: { name: this.composer.name }
|
||||
})
|
||||
},
|
||||
openDetails() {
|
||||
this.showDetailsModal = true
|
||||
},
|
||||
play() {
|
||||
webapi.player_play_expression(this.expression, true)
|
||||
},
|
||||
showDetails() {
|
||||
this.showDetailsModal = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ import TabsMusic from '@/components/TabsMusic.vue'
|
||||
import webapi from '@/webapi'
|
||||
|
||||
const dataObject = {
|
||||
load(to) {
|
||||
load() {
|
||||
return webapi.library_composers('music')
|
||||
},
|
||||
set(vm, response) {
|
||||
@ -45,7 +45,7 @@ export default {
|
||||
TabsMusic
|
||||
},
|
||||
beforeRouteEnter(to, from, next) {
|
||||
dataObject.load(to).then((response) => {
|
||||
dataObject.load().then((response) => {
|
||||
next((vm) => dataObject.set(vm, response))
|
||||
})
|
||||
},
|
||||
|
@ -6,7 +6,7 @@
|
||||
</template>
|
||||
<template #heading-right>
|
||||
<control-button
|
||||
:button="{ handler: showDetails, icon: 'dots-horizontal' }"
|
||||
:button="{ handler: openDetails, icon: 'dots-horizontal' }"
|
||||
/>
|
||||
<control-button
|
||||
:button="{ handler: play, icon: 'play', key: 'actions.play' }"
|
||||
@ -18,7 +18,7 @@
|
||||
<list-tracks
|
||||
:expression="expression"
|
||||
:items="tracks"
|
||||
:show-icon="true"
|
||||
icon="file-music-outline"
|
||||
/>
|
||||
<modal-dialog-directory
|
||||
:item="current"
|
||||
@ -120,12 +120,12 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
openDetails() {
|
||||
this.showDetailsModal = true
|
||||
},
|
||||
play() {
|
||||
webapi.player_play_expression(this.expression, false)
|
||||
},
|
||||
showDetails() {
|
||||
this.showDetailsModal = true
|
||||
},
|
||||
transform(path) {
|
||||
return { name: path.slice(path.lastIndexOf('/') + 1), path }
|
||||
}
|
||||
|
@ -9,7 +9,7 @@
|
||||
</template>
|
||||
<template #heading-right>
|
||||
<control-button
|
||||
:button="{ handler: showDetails, icon: 'dots-horizontal' }"
|
||||
:button="{ handler: openDetails, icon: 'dots-horizontal' }"
|
||||
/>
|
||||
<control-button
|
||||
:button="{ handler: play, icon: 'shuffle', key: 'actions.shuffle' }"
|
||||
@ -95,6 +95,9 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
openDetails() {
|
||||
this.showDetailsModal = true
|
||||
},
|
||||
openTracks() {
|
||||
this.showDetailsModal = false
|
||||
this.$router.push({
|
||||
@ -108,9 +111,6 @@ export default {
|
||||
`genre is "${this.genre.name}" and media_kind is ${this.media_kind}`,
|
||||
true
|
||||
)
|
||||
},
|
||||
showDetails() {
|
||||
this.showDetailsModal = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,7 @@
|
||||
v-text="$t('options.sort.title')"
|
||||
/>
|
||||
<control-dropdown
|
||||
v-model:value="uiStore.genre_tracks_sort"
|
||||
v-model:value="uiStore.genreTracksSort"
|
||||
:options="groupings"
|
||||
/>
|
||||
</div>
|
||||
@ -21,7 +21,7 @@
|
||||
</template>
|
||||
<template #heading-right>
|
||||
<control-button
|
||||
:button="{ handler: showDetails, icon: 'dots-horizontal' }"
|
||||
:button="{ handler: openDetails, icon: 'dots-horizontal' }"
|
||||
/>
|
||||
<control-button
|
||||
:button="{ handler: play, icon: 'shuffle', key: 'actions.shuffle' }"
|
||||
@ -131,7 +131,7 @@ export default {
|
||||
},
|
||||
tracks() {
|
||||
const { options } = this.groupings.find(
|
||||
(grouping) => grouping.id === this.uiStore.genre_tracks_sort
|
||||
(grouping) => grouping.id === this.uiStore.genreTracksSort
|
||||
)
|
||||
return this.trackList.group(options)
|
||||
}
|
||||
@ -148,7 +148,7 @@ export default {
|
||||
play() {
|
||||
webapi.player_play_expression(this.expression, true)
|
||||
},
|
||||
showDetails() {
|
||||
openDetails() {
|
||||
this.showDetailsModal = true
|
||||
}
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ import TabsMusic from '@/components/TabsMusic.vue'
|
||||
import webapi from '@/webapi'
|
||||
|
||||
const dataObject = {
|
||||
load(to) {
|
||||
load() {
|
||||
return webapi.library_genres('music')
|
||||
},
|
||||
set(vm, response) {
|
||||
@ -45,7 +45,7 @@ export default {
|
||||
TabsMusic
|
||||
},
|
||||
beforeRouteEnter(to, from, next) {
|
||||
dataObject.load(to).then((response) => {
|
||||
dataObject.load().then((response) => {
|
||||
next((vm) => dataObject.set(vm, response))
|
||||
})
|
||||
},
|
||||
|
@ -50,7 +50,7 @@ import TabsMusic from '@/components/TabsMusic.vue'
|
||||
import webapi from '@/webapi'
|
||||
|
||||
const dataObject = {
|
||||
load(to) {
|
||||
load() {
|
||||
return Promise.all([
|
||||
webapi.search({
|
||||
expression:
|
||||
@ -82,14 +82,14 @@ export default {
|
||||
TabsMusic
|
||||
},
|
||||
beforeRouteEnter(to, from, next) {
|
||||
dataObject.load(to).then((response) => {
|
||||
dataObject.load().then((response) => {
|
||||
next((vm) => dataObject.set(vm, response))
|
||||
})
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
albums: [],
|
||||
tracks: { items: [] }
|
||||
tracks: null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ import { useSettingsStore } from '@/stores/settings'
|
||||
import webapi from '@/webapi'
|
||||
|
||||
const dataObject = {
|
||||
load(to) {
|
||||
load() {
|
||||
const limit = useSettingsStore().recently_added_limit
|
||||
return webapi.search({
|
||||
expression:
|
||||
@ -45,7 +45,7 @@ export default {
|
||||
name: 'PageMusicRecentlyAdded',
|
||||
components: { ContentWithHeading, HeadingTitle, ListAlbums, TabsMusic },
|
||||
beforeRouteEnter(to, from, next) {
|
||||
dataObject.load(to).then((response) => {
|
||||
dataObject.load().then((response) => {
|
||||
next((vm) => dataObject.set(vm, response))
|
||||
})
|
||||
},
|
||||
|
@ -23,7 +23,7 @@ import TabsMusic from '@/components/TabsMusic.vue'
|
||||
import webapi from '@/webapi'
|
||||
|
||||
const dataObject = {
|
||||
load(to) {
|
||||
load() {
|
||||
return webapi.search({
|
||||
expression:
|
||||
'time_played after 8 weeks ago and media_kind is music order by time_played desc',
|
||||
@ -40,7 +40,7 @@ export default {
|
||||
name: 'PageMusicRecentlyPlayed',
|
||||
components: { ContentWithHeading, HeadingTitle, ListTracks, TabsMusic },
|
||||
beforeRouteEnter(to, from, next) {
|
||||
dataObject.load(to).then((response) => {
|
||||
dataObject.load().then((response) => {
|
||||
next((vm) => dataObject.set(vm, response))
|
||||
})
|
||||
},
|
||||
|
@ -50,7 +50,7 @@ import TabsMusic from '@/components/TabsMusic.vue'
|
||||
import webapi from '@/webapi'
|
||||
|
||||
const dataObject = {
|
||||
load(to) {
|
||||
load() {
|
||||
return webapi.spotify().then(({ data }) => {
|
||||
const spotifyApi = new SpotifyWebApi()
|
||||
spotifyApi.setAccessToken(data.webapi_token)
|
||||
@ -82,7 +82,7 @@ export default {
|
||||
TabsMusic
|
||||
},
|
||||
beforeRouteEnter(to, from, next) {
|
||||
dataObject.load(to).then((response) => {
|
||||
dataObject.load().then((response) => {
|
||||
next((vm) => dataObject.set(vm, response))
|
||||
})
|
||||
},
|
||||
|
@ -21,7 +21,7 @@ import TabsMusic from '@/components/TabsMusic.vue'
|
||||
import webapi from '@/webapi'
|
||||
|
||||
const dataObject = {
|
||||
load(to) {
|
||||
load() {
|
||||
return webapi.spotify().then(({ data }) => {
|
||||
const spotifyApi = new SpotifyWebApi()
|
||||
spotifyApi.setAccessToken(data.webapi_token)
|
||||
@ -45,7 +45,7 @@ export default {
|
||||
TabsMusic
|
||||
},
|
||||
beforeRouteEnter(to, from, next) {
|
||||
dataObject.load(to).then((response) => {
|
||||
dataObject.load().then((response) => {
|
||||
next((vm) => dataObject.set(vm, response))
|
||||
})
|
||||
},
|
||||
|
@ -9,21 +9,21 @@
|
||||
:album="track.album"
|
||||
class="is-clickable is-big"
|
||||
:class="{ 'is-masked': lyricsStore.active }"
|
||||
@click="openDialog(track)"
|
||||
@click="openDetails(track)"
|
||||
/>
|
||||
<lyrics-pane v-if="lyricsStore.active" />
|
||||
<control-slider
|
||||
v-model:value="track_progress"
|
||||
v-model:value="trackProgress"
|
||||
class="mt-5"
|
||||
:disabled="is_live"
|
||||
:max="track_progress_max"
|
||||
:disabled="isLive"
|
||||
:max="trackProgressMax"
|
||||
@change="seek"
|
||||
@mousedown="start_dragging"
|
||||
@mouseup="end_dragging"
|
||||
@mousedown="startDragging"
|
||||
@mouseup="endDragging"
|
||||
/>
|
||||
<div class="is-flex is-justify-content-space-between">
|
||||
<p class="subtitle is-7" v-text="track_elapsed_time" />
|
||||
<p class="subtitle is-7" v-text="track_total_time" />
|
||||
<p class="subtitle is-7" v-text="trackElapsedTime" />
|
||||
<p class="subtitle is-7" v-text="trackTotalTime" />
|
||||
</div>
|
||||
<p class="title is-5" v-text="track.title" />
|
||||
<p class="title is-6" v-text="track.artist" />
|
||||
@ -83,8 +83,8 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
INTERVAL,
|
||||
interval_id: 0,
|
||||
is_dragged: false,
|
||||
intervalId: 0,
|
||||
isDragged: false,
|
||||
selectedItem: {},
|
||||
showDetailsModal: false
|
||||
}
|
||||
@ -109,16 +109,16 @@ export default {
|
||||
}
|
||||
return null
|
||||
},
|
||||
is_live() {
|
||||
isLive() {
|
||||
return this.track.length_ms === 0
|
||||
},
|
||||
track() {
|
||||
return this.queueStore.current
|
||||
},
|
||||
track_elapsed_time() {
|
||||
return this.$filters.toTimecode(this.track_progress * INTERVAL)
|
||||
trackElapsedTime() {
|
||||
return this.$filters.toTimecode(this.trackProgress * INTERVAL)
|
||||
},
|
||||
track_progress: {
|
||||
trackProgress: {
|
||||
get() {
|
||||
return Math.floor(this.playerStore.item_progress_ms / INTERVAL)
|
||||
},
|
||||
@ -126,23 +126,23 @@ export default {
|
||||
this.playerStore.item_progress_ms = value * INTERVAL
|
||||
}
|
||||
},
|
||||
track_progress_max() {
|
||||
return this.is_live ? 1 : Math.floor(this.track.length_ms / INTERVAL)
|
||||
trackProgressMax() {
|
||||
return this.isLive ? 1 : Math.floor(this.track.length_ms / INTERVAL)
|
||||
},
|
||||
track_total_time() {
|
||||
return this.is_live
|
||||
trackTotalTime() {
|
||||
return this.isLive
|
||||
? this.$t('page.now-playing.live')
|
||||
: this.$filters.toTimecode(this.track.length_ms)
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
'playerStore.state'(newState) {
|
||||
if (this.interval_id > 0) {
|
||||
window.clearTimeout(this.interval_id)
|
||||
this.interval_id = 0
|
||||
if (this.intervalId > 0) {
|
||||
window.clearTimeout(this.intervalId)
|
||||
this.intervalId = 0
|
||||
}
|
||||
if (newState === 'play') {
|
||||
this.interval_id = window.setInterval(this.tick, INTERVAL)
|
||||
this.intervalId = window.setInterval(this.tick, INTERVAL)
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -150,35 +150,35 @@ export default {
|
||||
webapi.player_status().then(({ data }) => {
|
||||
this.playerStore.$state = data
|
||||
if (this.playerStore.state === 'play') {
|
||||
this.interval_id = window.setInterval(this.tick, INTERVAL)
|
||||
this.intervalId = window.setInterval(this.tick, INTERVAL)
|
||||
}
|
||||
})
|
||||
},
|
||||
unmounted() {
|
||||
if (this.interval_id > 0) {
|
||||
window.clearTimeout(this.interval_id)
|
||||
this.interval_id = 0
|
||||
if (this.intervalId > 0) {
|
||||
window.clearTimeout(this.intervalId)
|
||||
this.intervalId = 0
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
end_dragging() {
|
||||
this.is_dragged = false
|
||||
endDragging() {
|
||||
this.isDragged = false
|
||||
},
|
||||
openDialog(item) {
|
||||
openDetails(item) {
|
||||
this.selectedItem = item
|
||||
this.showDetailsModal = true
|
||||
},
|
||||
seek() {
|
||||
if (!this.is_live) {
|
||||
webapi.player_seek_to_pos(this.track_progress * INTERVAL)
|
||||
if (!this.isLive) {
|
||||
webapi.player_seek_to_pos(this.trackProgress * INTERVAL)
|
||||
}
|
||||
},
|
||||
start_dragging() {
|
||||
this.is_dragged = true
|
||||
startDragging() {
|
||||
this.isDragged = true
|
||||
},
|
||||
tick() {
|
||||
if (!this.is_dragged) {
|
||||
this.track_progress += 1
|
||||
if (!this.isDragged) {
|
||||
this.trackProgress += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ const dataObject = {
|
||||
},
|
||||
set(vm, response) {
|
||||
vm.playlist = response[0].data
|
||||
vm.playlists_list = new GroupedList(response[1].data)
|
||||
vm.playlistList = new GroupedList(response[1].data)
|
||||
}
|
||||
}
|
||||
|
||||
@ -54,7 +54,7 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
playlist: {},
|
||||
playlists_list: new GroupedList()
|
||||
playlistList: new GroupedList()
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@ -68,7 +68,7 @@ export default {
|
||||
}
|
||||
},
|
||||
playlists() {
|
||||
return this.playlists_list.group({
|
||||
return this.playlistList.group({
|
||||
filters: [
|
||||
(playlist) =>
|
||||
playlist.folder ||
|
||||
|
@ -6,7 +6,7 @@
|
||||
</template>
|
||||
<template #heading-right>
|
||||
<control-button
|
||||
:button="{ handler: showDetails, icon: 'dots-horizontal' }"
|
||||
:button="{ handler: openDetails, icon: 'dots-horizontal' }"
|
||||
/>
|
||||
<control-button
|
||||
:button="{
|
||||
@ -91,7 +91,7 @@ export default {
|
||||
play() {
|
||||
webapi.player_play_uri(this.uris, true)
|
||||
},
|
||||
showDetails() {
|
||||
openDetails() {
|
||||
this.showDetailsModal = true
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@
|
||||
</template>
|
||||
<template #heading-right>
|
||||
<control-button
|
||||
:button="{ handler: showDetails, icon: 'dots-horizontal' }"
|
||||
:button="{ handler: openDetails, icon: 'dots-horizontal' }"
|
||||
/>
|
||||
<control-button
|
||||
:button="{
|
||||
@ -153,7 +153,7 @@ export default {
|
||||
this.showDetailsModal = false
|
||||
webapi.player_play_uri(this.playlist.uri, true)
|
||||
},
|
||||
showDetails() {
|
||||
openDetails() {
|
||||
this.showDetailsModal = true
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,7 @@
|
||||
:button="{ handler: play, icon: 'play', key: 'actions.play' }"
|
||||
/>
|
||||
<control-button
|
||||
:button="{ handler: showDetails, icon: 'dots-horizontal' }"
|
||||
:button="{ handler: openDetails, icon: 'dots-horizontal' }"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
@ -25,7 +25,7 @@
|
||||
:artist="album.artist"
|
||||
:album="album.name"
|
||||
class="is-clickable is-medium"
|
||||
@click="showDetails"
|
||||
@click="openDetails"
|
||||
/>
|
||||
</template>
|
||||
<template #content>
|
||||
@ -55,7 +55,7 @@
|
||||
<br />
|
||||
</template>
|
||||
<template #name>
|
||||
<b v-text="rss_playlist_to_remove.name" />
|
||||
<b v-text="playlistToRemove.name" />
|
||||
</template>
|
||||
</i18n-t>
|
||||
</template>
|
||||
@ -106,7 +106,7 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
album: {},
|
||||
rss_playlist_to_remove: {},
|
||||
playlistToRemove: {},
|
||||
showDetailsModal: false,
|
||||
showRemovePodcastModal: false,
|
||||
tracks: new GroupedList()
|
||||
@ -133,7 +133,7 @@ export default {
|
||||
webapi
|
||||
.library_track_playlists(this.tracks.items[0].id)
|
||||
.then(({ data }) => {
|
||||
;[this.rss_playlist_to_remove] = data.items.filter(
|
||||
;[this.playlistToRemove] = data.items.filter(
|
||||
(pl) => pl.type === 'rss'
|
||||
)
|
||||
this.showRemovePodcastModal = true
|
||||
@ -150,13 +150,11 @@ export default {
|
||||
},
|
||||
removePodcast() {
|
||||
this.showRemovePodcastModal = false
|
||||
webapi
|
||||
.library_playlist_delete(this.rss_playlist_to_remove.id)
|
||||
.then(() => {
|
||||
this.$router.replace({ name: 'podcasts' })
|
||||
})
|
||||
webapi.library_playlist_delete(this.playlistToRemove.id).then(() => {
|
||||
this.$router.replace({ name: 'podcasts' })
|
||||
})
|
||||
},
|
||||
showDetails() {
|
||||
openDetails() {
|
||||
this.showDetailsModal = true
|
||||
}
|
||||
}
|
||||
|
@ -53,12 +53,12 @@
|
||||
<list-item-queue-item
|
||||
:item="element"
|
||||
:position="index"
|
||||
:current_position="current_position"
|
||||
:current-position="currentPosition"
|
||||
:hide-read-items="uiStore.hideReadItems"
|
||||
:editing="editing"
|
||||
>
|
||||
<template #actions>
|
||||
<a v-if="!editing" @click.prevent.stop="openDialog(element)">
|
||||
<a v-if="!editing" @click.prevent.stop="openDetails(element)">
|
||||
<mdicon
|
||||
class="icon has-text-grey"
|
||||
name="dots-vertical"
|
||||
@ -139,7 +139,7 @@ export default {
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
current_position() {
|
||||
currentPosition() {
|
||||
return this.queueStore.current?.position ?? -1
|
||||
},
|
||||
heading() {
|
||||
@ -166,7 +166,7 @@ export default {
|
||||
},
|
||||
moveItem(event) {
|
||||
const oldPosition =
|
||||
event.oldIndex + (this.uiStore.hideReadItems && this.current_position)
|
||||
event.oldIndex + (this.uiStore.hideReadItems && this.currentPosition)
|
||||
const item = this.items[oldPosition]
|
||||
const newPosition = item.position + (event.newIndex - event.oldIndex)
|
||||
if (newPosition !== oldPosition) {
|
||||
@ -176,7 +176,7 @@ export default {
|
||||
openAddStreamDialog() {
|
||||
this.showAddStreamDialog = true
|
||||
},
|
||||
openDialog(item) {
|
||||
openDetails(item) {
|
||||
this.selectedItem = item
|
||||
this.showDetailsModal = true
|
||||
},
|
||||
|
@ -33,7 +33,7 @@
|
||||
/>
|
||||
<div class="content">
|
||||
<control-setting-switch
|
||||
v-if="spotify.spotify_logged_in"
|
||||
v-if="servicesStore.spotify_logged_in"
|
||||
category="artwork"
|
||||
name="use_artwork_source_spotify"
|
||||
>
|
||||
@ -95,11 +95,6 @@ export default {
|
||||
},
|
||||
setup() {
|
||||
return { servicesStore: useServicesStore() }
|
||||
},
|
||||
computed: {
|
||||
spotify() {
|
||||
return this.servicesStore.spotify
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
@ -47,8 +47,8 @@
|
||||
<div class="control">
|
||||
<a
|
||||
class="button is-danger"
|
||||
@click="logout_spotify"
|
||||
v-text="$t('page.settings.services.logout')"
|
||||
@click="logoutSpotify"
|
||||
v-text="$t('actions.logout')"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -75,11 +75,11 @@
|
||||
<a
|
||||
class="button is-danger"
|
||||
@click="logoutLastfm"
|
||||
v-text="$t('page.settings.services.logout')"
|
||||
v-text="$t('actions.logout')"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="!lastfm.scrobbling_enabled">
|
||||
<form @submit.prevent="login_lastfm">
|
||||
<form @submit.prevent="loginLastfm">
|
||||
<div class="field is-grouped">
|
||||
<div class="control">
|
||||
<input
|
||||
@ -106,7 +106,7 @@
|
||||
<button
|
||||
class="button"
|
||||
type="submit"
|
||||
v-text="$t('page.settings.services.login')"
|
||||
v-text="$t('actions.login')"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -172,7 +172,7 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
login_lastfm() {
|
||||
loginLastfm() {
|
||||
webapi.lastfm_login(this.lastfm_login).then((response) => {
|
||||
this.lastfm_login.user = ''
|
||||
this.lastfm_login.password = ''
|
||||
@ -190,7 +190,7 @@ export default {
|
||||
logoutLastfm() {
|
||||
webapi.lastfm_logout()
|
||||
},
|
||||
logout_spotify() {
|
||||
logoutSpotify() {
|
||||
webapi.spotify_logout()
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@
|
||||
</template>
|
||||
<template #content>
|
||||
<div v-if="pairing.active">
|
||||
<form @submit.prevent="kickoff_pairing">
|
||||
<form @submit.prevent="kickoffPairing">
|
||||
<label class="label has-text-weight-normal content">
|
||||
<span v-text="$t('page.settings.devices.pairing-request')" />
|
||||
<b v-text="pairing.remote" />
|
||||
@ -17,7 +17,7 @@
|
||||
<div class="field is-grouped">
|
||||
<div class="control">
|
||||
<input
|
||||
v-model="pairing_req.pin"
|
||||
v-model="pairingRequest.pin"
|
||||
class="input"
|
||||
inputmode="numeric"
|
||||
pattern="[\d]{4}"
|
||||
@ -62,12 +62,12 @@
|
||||
<form
|
||||
v-if="output.needs_auth_key"
|
||||
class="mb-5"
|
||||
@submit.prevent="kickoff_verification(output.id)"
|
||||
@submit.prevent="kickoffVerification(output.id)"
|
||||
>
|
||||
<div class="field is-grouped">
|
||||
<div class="control">
|
||||
<input
|
||||
v-model="verification_req.pin"
|
||||
v-model="verificationRequest.pin"
|
||||
class="input"
|
||||
inputmode="numeric"
|
||||
pattern="[\d]{4}"
|
||||
@ -106,8 +106,8 @@ export default {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
pairing_req: { pin: '' },
|
||||
verification_req: { pin: '' }
|
||||
pairingRequest: { pin: '' },
|
||||
verificationRequest: { pin: '' }
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@ -119,11 +119,11 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
kickoff_pairing() {
|
||||
webapi.pairing_kickoff(this.pairing_req)
|
||||
kickoffPairing() {
|
||||
webapi.pairing_kickoff(this.pairingRequest)
|
||||
},
|
||||
kickoff_verification(identifier) {
|
||||
webapi.output_update(identifier, this.verification_req)
|
||||
kickoffVerification(identifier) {
|
||||
webapi.output_update(identifier, this.verificationRequest)
|
||||
},
|
||||
toggleOutput(identifier) {
|
||||
webapi.output_toggle(identifier)
|
||||
|
@ -8,7 +8,10 @@
|
||||
/>
|
||||
</template>
|
||||
<template #content>
|
||||
<control-dropdown v-model:value="locale" :options="locales" />
|
||||
<control-dropdown
|
||||
v-model:value="locale"
|
||||
:options="settingsStore.locales"
|
||||
/>
|
||||
</template>
|
||||
</content-with-heading>
|
||||
<content-with-heading>
|
||||
@ -198,14 +201,6 @@ export default {
|
||||
set(locale) {
|
||||
this.$i18n.locale = locale
|
||||
}
|
||||
},
|
||||
locales: {
|
||||
get() {
|
||||
return this.$i18n.availableLocales.map((item) => ({
|
||||
id: item,
|
||||
name: this.$t(`language.${item}`)
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -33,5 +33,8 @@ export const useNotificationsStore = defineStore('NotificationsStore', {
|
||||
}
|
||||
}
|
||||
},
|
||||
getters: {
|
||||
isEmpty: (state) => state.list.length <= 0
|
||||
},
|
||||
state: () => ({ list: [], nextId: 1 })
|
||||
})
|
||||
|
@ -1,4 +1,7 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import i18n from '@/i18n'
|
||||
|
||||
const { t, availableLocales } = i18n.global
|
||||
|
||||
export const useSettingsStore = defineStore('SettingsStore', {
|
||||
actions: {
|
||||
@ -25,6 +28,12 @@ export const useSettingsStore = defineStore('SettingsStore', {
|
||||
}
|
||||
},
|
||||
getters: {
|
||||
locales(state) {
|
||||
return availableLocales.map((item) => ({
|
||||
id: item,
|
||||
name: t(`language.${item}`)
|
||||
}))
|
||||
},
|
||||
recently_added_limit: (state) =>
|
||||
state.setting('webinterface', 'recently_added_limit')?.value ?? 100,
|
||||
show_composer_for_genre: (state) =>
|
||||
|
@ -19,12 +19,12 @@ export const useUIStore = defineStore('UIStore', {
|
||||
}
|
||||
},
|
||||
state: () => ({
|
||||
albums_sort: 1,
|
||||
artist_albums_sort: 1,
|
||||
artist_tracks_sort: 1,
|
||||
artists_sort: 1,
|
||||
composer_tracks_sort: 1,
|
||||
genre_tracks_sort: 1,
|
||||
albumsSort: 1,
|
||||
artistAlbumsSort: 1,
|
||||
artistTracksSort: 1,
|
||||
artistsSort: 1,
|
||||
composerTracksSort: 1,
|
||||
genreTracksSort: 1,
|
||||
hideReadItems: false,
|
||||
hideSingles: false,
|
||||
hideSpotify: false,
|
||||
|
@ -34,11 +34,12 @@
|
||||
</div>
|
||||
</nav>
|
||||
<slot name="content" />
|
||||
<nav v-if="$slots.footer" class="level mt-4">
|
||||
<div class="level-item">
|
||||
<slot name="footer" />
|
||||
</div>
|
||||
</nav>
|
||||
<div
|
||||
v-if="$slots.footer"
|
||||
class="is-flex is-justify-content-center mt-4"
|
||||
>
|
||||
<slot name="footer" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
Loading…
x
Reference in New Issue
Block a user