mirror of
https://github.com/owntone/owntone-server.git
synced 2025-11-07 21:03:00 -05:00
[web] Refactor API calls
This commit is contained in:
@@ -32,7 +32,7 @@
|
||||
"devDependencies": {
|
||||
"@intlify/unplugin-vue-i18n": "^6.0.8",
|
||||
"@vitejs/plugin-vue": "^5.2.3",
|
||||
"eslint": "^9.25.1",
|
||||
"eslint": "^9.26.0",
|
||||
"eslint-config-prettier": "^10.1.2",
|
||||
"eslint-plugin-vue": "^10.1.0",
|
||||
"prettier": "^3.5.3",
|
||||
|
||||
@@ -28,6 +28,9 @@ import ModalDialogUpdate from '@/components/ModalDialogUpdate.vue'
|
||||
import NavbarBottom from '@/components/NavbarBottom.vue'
|
||||
import NavbarTop from '@/components/NavbarTop.vue'
|
||||
import ReconnectingWebSocket from 'reconnectingwebsocket'
|
||||
import configuration from '@/api/configuration'
|
||||
import library from '@/api/library'
|
||||
import services from '@/api/services'
|
||||
import { useConfigurationStore } from '@/stores/configuration'
|
||||
import { useLibraryStore } from '@/stores/library'
|
||||
import { useLyricsStore } from '@/stores/lyrics'
|
||||
@@ -39,7 +42,6 @@ import { useRemotesStore } from './stores/remotes'
|
||||
import { useServicesStore } from '@/stores/services'
|
||||
import { useSettingsStore } from '@/stores/settings'
|
||||
import { useUIStore } from './stores/ui'
|
||||
import webapi from '@/webapi'
|
||||
|
||||
export default {
|
||||
name: 'App',
|
||||
@@ -96,8 +98,8 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
connect() {
|
||||
webapi
|
||||
.config()
|
||||
configuration
|
||||
.list()
|
||||
.then((data) => {
|
||||
this.configurationStore.$state = data
|
||||
this.uiStore.hideSingles = data.hide_singles
|
||||
@@ -133,29 +135,28 @@ export default {
|
||||
})
|
||||
)
|
||||
this.updateOutputs()
|
||||
this.updatePlayerStatus()
|
||||
this.updateLibraryStats()
|
||||
this.updatePlayer()
|
||||
this.updateLibrary()
|
||||
this.updateSettings()
|
||||
this.updateQueue()
|
||||
this.updateSpotify()
|
||||
this.updateLastfm()
|
||||
this.updatePairing()
|
||||
this.updateRemotes()
|
||||
}
|
||||
|
||||
let updateThrottled = false
|
||||
|
||||
const updateInfo = () => {
|
||||
if (updateThrottled) {
|
||||
return
|
||||
}
|
||||
this.updateOutputs()
|
||||
this.updatePlayerStatus()
|
||||
this.updateLibraryStats()
|
||||
this.updatePlayer()
|
||||
this.updateLibrary()
|
||||
this.updateSettings()
|
||||
this.updateQueue()
|
||||
this.updateSpotify()
|
||||
this.updateLastfm()
|
||||
this.updatePairing()
|
||||
this.updateRemotes()
|
||||
updateThrottled = true
|
||||
setTimeout(() => {
|
||||
updateThrottled = false
|
||||
@@ -171,34 +172,25 @@ export default {
|
||||
|
||||
socket.onmessage = (response) => {
|
||||
const data = JSON.parse(response.data)
|
||||
if (
|
||||
data.notify.includes('update') ||
|
||||
data.notify.includes('database')
|
||||
) {
|
||||
this.updateLibraryStats()
|
||||
}
|
||||
if (
|
||||
data.notify.includes('player') ||
|
||||
data.notify.includes('options') ||
|
||||
data.notify.includes('volume')
|
||||
) {
|
||||
this.updatePlayerStatus()
|
||||
}
|
||||
if (data.notify.includes('outputs') || data.notify.includes('volume')) {
|
||||
this.updateOutputs()
|
||||
}
|
||||
if (data.notify.includes('queue')) {
|
||||
this.updateQueue()
|
||||
}
|
||||
if (data.notify.includes('spotify')) {
|
||||
this.updateSpotify()
|
||||
}
|
||||
if (data.notify.includes('lastfm')) {
|
||||
this.updateLastfm()
|
||||
}
|
||||
if (data.notify.includes('pairing')) {
|
||||
this.updatePairing()
|
||||
}
|
||||
const notify = new Set(data.notify || [])
|
||||
const handlers = [
|
||||
{ handler: this.updateLibrary, triggers: ['update', 'database'] },
|
||||
{
|
||||
handler: this.updatePlayer,
|
||||
triggers: ['player', 'options', 'volume']
|
||||
},
|
||||
{ handler: this.updateOutputs, triggers: ['outputs', 'volume'] },
|
||||
{ handler: this.updateQueue, triggers: ['queue'] },
|
||||
{ handler: this.updateSpotify, triggers: ['spotify'] },
|
||||
{ handler: this.updateLastfm, triggers: ['lastfm'] },
|
||||
{ handler: this.updateRemotes, triggers: ['pairing'] },
|
||||
{ handler: this.updateLyrics, triggers: ['player', 'queue'] }
|
||||
]
|
||||
handlers.forEach(({ handler, triggers }) => {
|
||||
if (triggers.some((key) => notify.has(key))) {
|
||||
handler.call(this)
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
createWebsocket() {
|
||||
@@ -223,22 +215,17 @@ export default {
|
||||
}
|
||||
},
|
||||
updateLastfm() {
|
||||
webapi.lastfm().then((data) => {
|
||||
services.lastfm().then((data) => {
|
||||
this.servicesStore.lastfm = data
|
||||
})
|
||||
},
|
||||
updateLibraryStats() {
|
||||
webapi.library_stats().then((data) => {
|
||||
this.libraryStore.$state = data
|
||||
})
|
||||
webapi.library_count('scan_kind is rss').then((data) => {
|
||||
this.libraryStore.rss = data
|
||||
})
|
||||
updateLibrary() {
|
||||
this.libraryStore.initialise()
|
||||
},
|
||||
updateLyrics() {
|
||||
const track = this.queueStore.current
|
||||
if (track?.track_id) {
|
||||
webapi.library_track(track.track_id).then((data) => {
|
||||
library.track(track.track_id).then((data) => {
|
||||
this.lyricsStore.lyrics = data.lyrics
|
||||
})
|
||||
} else {
|
||||
@@ -246,34 +233,22 @@ export default {
|
||||
}
|
||||
},
|
||||
updateOutputs() {
|
||||
webapi.outputs().then((data) => {
|
||||
this.outputsStore.outputs = data.outputs
|
||||
})
|
||||
this.outputsStore.initialise()
|
||||
},
|
||||
updatePairing() {
|
||||
webapi.pairing().then((data) => {
|
||||
this.remotesStore.$state = data
|
||||
})
|
||||
updateRemotes() {
|
||||
this.remotesStore.initialise()
|
||||
},
|
||||
updatePlayerStatus() {
|
||||
webapi.player_status().then((data) => {
|
||||
this.playerStore.$state = data
|
||||
this.updateLyrics()
|
||||
})
|
||||
updatePlayer() {
|
||||
this.playerStore.initialise()
|
||||
},
|
||||
updateQueue() {
|
||||
webapi.queue().then((data) => {
|
||||
this.queueStore.$state = data
|
||||
this.updateLyrics()
|
||||
})
|
||||
this.queueStore.initialise()
|
||||
},
|
||||
updateSettings() {
|
||||
webapi.settings().then((data) => {
|
||||
this.settingsStore.$state = data
|
||||
})
|
||||
this.settingsStore.initialise()
|
||||
},
|
||||
updateSpotify() {
|
||||
webapi.spotify().then((data) => {
|
||||
services.spotify().then((data) => {
|
||||
this.servicesStore.spotify = data
|
||||
if (this.timerId > 0) {
|
||||
window.clearTimeout(this.timerId)
|
||||
|
||||
7
web-src/src/api/configuration.js
Normal file
7
web-src/src/api/configuration.js
Normal file
@@ -0,0 +1,7 @@
|
||||
import api from '@/api'
|
||||
|
||||
export default {
|
||||
list() {
|
||||
return api.get('./api/config')
|
||||
}
|
||||
}
|
||||
24
web-src/src/api/index.js
Normal file
24
web-src/src/api/index.js
Normal file
@@ -0,0 +1,24 @@
|
||||
import api from 'axios'
|
||||
import i18n from '@/i18n'
|
||||
import { useNotificationsStore } from '@/stores/notifications'
|
||||
|
||||
const { t } = i18n.global
|
||||
|
||||
api.interceptors.response.use(
|
||||
(response) => response.data,
|
||||
(error) => {
|
||||
if (error.request.status && error.request.responseURL) {
|
||||
useNotificationsStore().add({
|
||||
text: t('server.request-failed', {
|
||||
cause: error.request.statusText,
|
||||
status: error.request.status,
|
||||
url: error.request.responseURL
|
||||
}),
|
||||
type: 'danger'
|
||||
})
|
||||
}
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
|
||||
export default api
|
||||
163
web-src/src/api/library.js
Normal file
163
web-src/src/api/library.js
Normal file
@@ -0,0 +1,163 @@
|
||||
import api from '@/api'
|
||||
|
||||
export default {
|
||||
add(url) {
|
||||
return api.post('./api/library/add', null, { params: { url } })
|
||||
},
|
||||
album(id) {
|
||||
return api.get(`./api/library/albums/${id}`)
|
||||
},
|
||||
albumTracks(id, filter = { limit: -1, offset: 0 }) {
|
||||
return api.get(`./api/library/albums/${id}/tracks`, {
|
||||
params: filter
|
||||
})
|
||||
},
|
||||
albums(media_kind) {
|
||||
return api.get('./api/library/albums', { params: { media_kind } })
|
||||
},
|
||||
artist(id) {
|
||||
return api.get(`./api/library/artists/${id}`)
|
||||
},
|
||||
artistAlbums(id) {
|
||||
return api.get(`./api/library/artists/${id}/albums`)
|
||||
},
|
||||
async artistTracks(artist) {
|
||||
const params = {
|
||||
expression: `songartistid is "${artist}"`,
|
||||
type: 'tracks'
|
||||
}
|
||||
const data = await api.get('./api/search', { params })
|
||||
return data.tracks
|
||||
},
|
||||
artists(media_kind) {
|
||||
return api.get('./api/library/artists', { params: { media_kind } })
|
||||
},
|
||||
composer(composer) {
|
||||
return api.get(`./api/library/composers/${encodeURIComponent(composer)}`)
|
||||
},
|
||||
async composerAlbums(composer) {
|
||||
const params = {
|
||||
expression: `composer is "${composer}" and media_kind is music`,
|
||||
type: 'albums'
|
||||
}
|
||||
const data = await api.get('./api/search', { params })
|
||||
return data.albums
|
||||
},
|
||||
async composerTracks(composer) {
|
||||
const params = {
|
||||
expression: `composer is "${composer}" and media_kind is music`,
|
||||
type: 'tracks'
|
||||
}
|
||||
const data = await api.get('./api/search', { params })
|
||||
return data.tracks
|
||||
},
|
||||
composers(media_kind) {
|
||||
return api.get('./api/library/composers', { params: { media_kind } })
|
||||
},
|
||||
files(directory) {
|
||||
return api.get('./api/library/files', { params: { directory } })
|
||||
},
|
||||
async genre(genre, mediaKind) {
|
||||
const params = {
|
||||
expression: `genre is "${genre}" and media_kind is ${mediaKind}`,
|
||||
type: 'genres'
|
||||
}
|
||||
const data = await api.get('./api/search', { params })
|
||||
return data.genres
|
||||
},
|
||||
async genreAlbums(genre, mediaKind) {
|
||||
const params = {
|
||||
expression: `genre is "${genre}" and media_kind is ${mediaKind}`,
|
||||
type: 'albums'
|
||||
}
|
||||
const data = await api.get('./api/search', { params })
|
||||
return data.albums
|
||||
},
|
||||
async genreTracks(genre, mediaKind) {
|
||||
const params = {
|
||||
expression: `genre is "${genre}" and media_kind is ${mediaKind}`,
|
||||
type: 'tracks'
|
||||
}
|
||||
const data = await api.get('./api/search', { params })
|
||||
return data.tracks
|
||||
},
|
||||
async genres(mediaKind) {
|
||||
const params = {
|
||||
expression: `media_kind is ${mediaKind}`,
|
||||
type: 'genres'
|
||||
}
|
||||
const data = await api.get('./api/search', { params })
|
||||
return data.genres
|
||||
},
|
||||
async newPodcastEpisodes() {
|
||||
const params = {
|
||||
expression:
|
||||
'media_kind is podcast and play_count = 0 ORDER BY time_added DESC',
|
||||
type: 'tracks'
|
||||
}
|
||||
const data = await api.get('./api/search', { params })
|
||||
return data.tracks
|
||||
},
|
||||
playlist(id) {
|
||||
return api.get(`./api/library/playlists/${id}`)
|
||||
},
|
||||
playlistDelete(id) {
|
||||
return api.delete(`./api/library/playlists/${id}`)
|
||||
},
|
||||
playlistFolder(id = 0) {
|
||||
return api.get(`./api/library/playlists/${id}/playlists`)
|
||||
},
|
||||
playlistTracks(id) {
|
||||
return api.get(`./api/library/playlists/${id}/tracks`)
|
||||
},
|
||||
async podcastEpisodes(id) {
|
||||
const params = {
|
||||
expression: `media_kind is podcast and songalbumid is "${id}" ORDER BY date_released DESC`,
|
||||
type: 'tracks'
|
||||
}
|
||||
const data = await api.get('./api/search', { params })
|
||||
return data.tracks
|
||||
},
|
||||
async radioStreams() {
|
||||
const params = {
|
||||
expression: 'data_kind is url and song_length = 0',
|
||||
media_kind: 'music',
|
||||
type: 'tracks'
|
||||
}
|
||||
const data = await api.get('./api/search', { params })
|
||||
return data.tracks
|
||||
},
|
||||
rescan(scan_kind) {
|
||||
return api.put('./api/rescan', null, { params: { scan_kind } })
|
||||
},
|
||||
rssCount() {
|
||||
return api.get('./api/library/count', {
|
||||
params: { expression: 'scan_kind is rss' }
|
||||
})
|
||||
},
|
||||
search(params) {
|
||||
return api.get('./api/search', { params })
|
||||
},
|
||||
state() {
|
||||
return api.get('./api/library')
|
||||
},
|
||||
track(id) {
|
||||
return api.get(`./api/library/tracks/${id}`)
|
||||
},
|
||||
trackPlaylists(id) {
|
||||
return api.get(`./api/library/tracks/${id}/playlists`)
|
||||
},
|
||||
update(scan_kind) {
|
||||
return api.put('./api/update', null, { params: { scan_kind } })
|
||||
},
|
||||
updateAlbum(id, attributes) {
|
||||
return api.put(`./api/library/albums/${id}/tracks`, null, {
|
||||
params: attributes
|
||||
})
|
||||
},
|
||||
updateTrack(id, attributes = {}) {
|
||||
return api.put(`./api/library/tracks/${id}`, null, {
|
||||
params: attributes
|
||||
})
|
||||
}
|
||||
}
|
||||
13
web-src/src/api/outputs.js
Normal file
13
web-src/src/api/outputs.js
Normal file
@@ -0,0 +1,13 @@
|
||||
import api from '@/api'
|
||||
|
||||
export default {
|
||||
toggle(id) {
|
||||
return api.put(`./api/outputs/${id}/toggle`)
|
||||
},
|
||||
state() {
|
||||
return api.get('./api/outputs')
|
||||
},
|
||||
update(id, output) {
|
||||
return api.put(`./api/outputs/${id}`, output)
|
||||
}
|
||||
}
|
||||
45
web-src/src/api/player.js
Normal file
45
web-src/src/api/player.js
Normal file
@@ -0,0 +1,45 @@
|
||||
import api from '@/api'
|
||||
|
||||
export default {
|
||||
consume(state) {
|
||||
return api.put(`./api/player/consume?state=${state}`)
|
||||
},
|
||||
next() {
|
||||
return api.put('./api/player/next')
|
||||
},
|
||||
outputVolume(outputId, outputVolume) {
|
||||
return api.put(
|
||||
`./api/player/volume?volume=${outputVolume}&output_id=${outputId}`
|
||||
)
|
||||
},
|
||||
pause() {
|
||||
return api.put('./api/player/pause')
|
||||
},
|
||||
play(params = {}) {
|
||||
return api.put('./api/player/play', null, { params })
|
||||
},
|
||||
previous() {
|
||||
return api.put('./api/player/previous')
|
||||
},
|
||||
repeat(mode) {
|
||||
return api.put(`./api/player/repeat?state=${mode}`)
|
||||
},
|
||||
seek(seekMs) {
|
||||
return api.put(`./api/player/seek?seek_ms=${seekMs}`)
|
||||
},
|
||||
seekToPosition(position) {
|
||||
return api.put(`./api/player/seek?position_ms=${position}`)
|
||||
},
|
||||
shuffle(state) {
|
||||
return api.put(`./api/player/shuffle?state=${state}`)
|
||||
},
|
||||
state() {
|
||||
return api.get('./api/player')
|
||||
},
|
||||
stop() {
|
||||
return api.put('./api/player/stop')
|
||||
},
|
||||
volume(volume) {
|
||||
return api.put(`./api/player/volume?volume=${volume}`)
|
||||
}
|
||||
}
|
||||
73
web-src/src/api/queue.js
Normal file
73
web-src/src/api/queue.js
Normal file
@@ -0,0 +1,73 @@
|
||||
import api from '@/api'
|
||||
import i18n from '@/i18n'
|
||||
import { useNotificationsStore } from '@/stores/notifications'
|
||||
import { useQueueStore } from '@/stores/queue'
|
||||
|
||||
const { t } = i18n.global
|
||||
|
||||
export default {
|
||||
state() {
|
||||
return api.get('./api/queue')
|
||||
},
|
||||
addUri(uris, next = false) {
|
||||
return this.addToQueue({ uris }, next)
|
||||
},
|
||||
addExpression(expression, next = false) {
|
||||
return this.addToQueue({ expression }, next)
|
||||
},
|
||||
async addToQueue(params, next = false) {
|
||||
if (next) {
|
||||
const { current } = useQueueStore()
|
||||
if (current?.id) {
|
||||
params.position = current.position + 1
|
||||
}
|
||||
}
|
||||
const data = await api.post('./api/queue/items/add', null, { params })
|
||||
useNotificationsStore().add({
|
||||
text: t('server.appended-tracks', { count: data.count }),
|
||||
timeout: 2000,
|
||||
type: 'info'
|
||||
})
|
||||
return data
|
||||
},
|
||||
clear() {
|
||||
return api.put('./api/queue/clear')
|
||||
},
|
||||
move(id, position) {
|
||||
return api.put(`./api/queue/items/${id}?new_position=${position}`)
|
||||
},
|
||||
playExpression(expression, shuffle, position) {
|
||||
const params = {
|
||||
clear: 'true',
|
||||
expression,
|
||||
playback: 'start',
|
||||
playback_from_position: position,
|
||||
shuffle
|
||||
}
|
||||
return api.post('./api/queue/items/add', null, { params })
|
||||
},
|
||||
playUri(uris, shuffle, position) {
|
||||
const params = {
|
||||
clear: 'true',
|
||||
playback: 'start',
|
||||
playback_from_position: position,
|
||||
shuffle,
|
||||
uris
|
||||
}
|
||||
return api.post('./api/queue/items/add', null, { params })
|
||||
},
|
||||
remove(id) {
|
||||
return api.delete(`./api/queue/items/${id}`)
|
||||
},
|
||||
async saveToPlaylist(name) {
|
||||
const response = await api.post('./api/queue/save', null, {
|
||||
params: { name }
|
||||
})
|
||||
useNotificationsStore().add({
|
||||
text: t('server.queue-saved', { name }),
|
||||
timeout: 2000,
|
||||
type: 'info'
|
||||
})
|
||||
return await Promise.resolve(response)
|
||||
}
|
||||
}
|
||||
10
web-src/src/api/remotes.js
Normal file
10
web-src/src/api/remotes.js
Normal file
@@ -0,0 +1,10 @@
|
||||
import api from '@/api'
|
||||
|
||||
export default {
|
||||
pair(pin) {
|
||||
return api.post('./api/pairing', { pin })
|
||||
},
|
||||
state() {
|
||||
return api.get('./api/pairing')
|
||||
}
|
||||
}
|
||||
19
web-src/src/api/services.js
Normal file
19
web-src/src/api/services.js
Normal file
@@ -0,0 +1,19 @@
|
||||
import api from '@/api'
|
||||
|
||||
export default {
|
||||
lastfm() {
|
||||
return api.get('./api/lastfm')
|
||||
},
|
||||
loginLastfm(credentials) {
|
||||
return api.post('./api/lastfm-login', credentials)
|
||||
},
|
||||
logoutLastfm() {
|
||||
return api.get('./api/lastfm-logout')
|
||||
},
|
||||
logoutSpotify() {
|
||||
return api.get('./api/spotify-logout')
|
||||
},
|
||||
spotify() {
|
||||
return api.get('./api/spotify')
|
||||
}
|
||||
}
|
||||
10
web-src/src/api/settings.js
Normal file
10
web-src/src/api/settings.js
Normal file
@@ -0,0 +1,10 @@
|
||||
import api from '@/api'
|
||||
|
||||
export default {
|
||||
state() {
|
||||
return api.get('./api/settings')
|
||||
},
|
||||
update(categoryName, option) {
|
||||
return api.put(`./api/settings/${categoryName}/${option.name}`, option)
|
||||
}
|
||||
}
|
||||
@@ -18,8 +18,8 @@
|
||||
|
||||
<script>
|
||||
import ControlSlider from '@/components/ControlSlider.vue'
|
||||
import player from '@/api/player'
|
||||
import { usePlayerStore } from '@/stores/player'
|
||||
import webapi from '@/webapi'
|
||||
|
||||
export default {
|
||||
name: 'ControlVolume',
|
||||
@@ -48,7 +48,7 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
changeVolume() {
|
||||
webapi.player_volume(this.player.volume)
|
||||
player.volume(this.player.volume)
|
||||
},
|
||||
toggle() {
|
||||
this.player.volume = this.player.volume > 0 ? 0 : this.volume
|
||||
|
||||
@@ -27,7 +27,8 @@
|
||||
|
||||
<script>
|
||||
import ControlSlider from '@/components/ControlSlider.vue'
|
||||
import webapi from '@/webapi'
|
||||
import outputs from '@/api/outputs'
|
||||
import player from '@/api/player'
|
||||
|
||||
export default {
|
||||
name: 'ControlOutputVolume',
|
||||
@@ -63,13 +64,10 @@ export default {
|
||||
|
||||
methods: {
|
||||
changeVolume() {
|
||||
webapi.player_output_volume(this.output.id, this.volume)
|
||||
player.outputVolume(this.output.id, this.volume)
|
||||
},
|
||||
toggle() {
|
||||
const values = {
|
||||
selected: !this.output.selected
|
||||
}
|
||||
webapi.output_update(this.output.id, values)
|
||||
outputs.update(this.output.id, { selected: !this.output.selected })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,9 +9,9 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import player from '@/api/player'
|
||||
import { usePlayerStore } from '@/stores/player'
|
||||
import { useQueueStore } from '@/stores/queue'
|
||||
import webapi from '@/webapi'
|
||||
|
||||
export default {
|
||||
name: 'ControlPlayerBack',
|
||||
@@ -40,9 +40,7 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
seek() {
|
||||
if (!this.disabled) {
|
||||
webapi.player_seek(this.offset * -1)
|
||||
}
|
||||
player.seek(this.offset * -1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
<template>
|
||||
<a :class="{ 'is-dark': playerStore.consume }" @click="toggle">
|
||||
<button :class="{ 'is-dark': playerStore.consume }" @click="toggle">
|
||||
<mdicon
|
||||
class="icon"
|
||||
name="fire"
|
||||
size="16"
|
||||
:title="$t('player.button.consume')"
|
||||
/>
|
||||
</a>
|
||||
</button>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import player from '@/api/player'
|
||||
import { usePlayerStore } from '@/stores/player'
|
||||
import webapi from '@/webapi'
|
||||
|
||||
export default {
|
||||
name: 'ControlPlayerConsume',
|
||||
@@ -22,7 +22,7 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
toggle() {
|
||||
webapi.player_consume(!this.playerStore.consume)
|
||||
player.consume(!this.playerStore.consume)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,9 +9,9 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import player from '@/api/player'
|
||||
import { usePlayerStore } from '@/stores/player'
|
||||
import { useQueueStore } from '@/stores/queue'
|
||||
import webapi from '@/webapi'
|
||||
|
||||
export default {
|
||||
name: 'ControlPlayerForward',
|
||||
@@ -40,9 +40,7 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
seek() {
|
||||
if (!this.disabled) {
|
||||
webapi.player_seek(this.offset)
|
||||
}
|
||||
player.seek(this.offset)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
<template>
|
||||
<a :class="{ 'is-dark': lyricsStore.active }" @click="lyricsStore.toggle">
|
||||
<button
|
||||
:class="{ 'is-dark': lyricsStore.active }"
|
||||
@click="lyricsStore.toggle"
|
||||
>
|
||||
<mdicon
|
||||
class="icon"
|
||||
:name="icon"
|
||||
:size="16"
|
||||
:title="$t('player.button.toggle-lyrics')"
|
||||
/>
|
||||
</a>
|
||||
</button>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import player from '@/api/player'
|
||||
import { useQueueStore } from '@/stores/queue'
|
||||
import webapi from '@/webapi'
|
||||
|
||||
export default {
|
||||
name: 'ControlPlayerNext',
|
||||
@@ -24,10 +24,7 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
next() {
|
||||
if (this.disabled) {
|
||||
return
|
||||
}
|
||||
webapi.player_next()
|
||||
player.next()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,16 +5,14 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { useNotificationsStore } from '@/stores/notifications'
|
||||
import player from '@/api/player'
|
||||
import { usePlayerStore } from '@/stores/player'
|
||||
import { useQueueStore } from '@/stores/queue'
|
||||
import webapi from '@/webapi'
|
||||
|
||||
export default {
|
||||
name: 'ControlPlayerPlay',
|
||||
setup() {
|
||||
return {
|
||||
notificationsStore: useNotificationsStore(),
|
||||
playerStore: usePlayerStore(),
|
||||
queueStore: useQueueStore()
|
||||
}
|
||||
@@ -34,24 +32,15 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
toggle() {
|
||||
if (this.disabled) {
|
||||
this.notificationsStore.add({
|
||||
text: this.$t('server.empty-queue'),
|
||||
timeout: 2000,
|
||||
topic: 'connection',
|
||||
type: 'info'
|
||||
})
|
||||
return
|
||||
}
|
||||
if (this.playerStore.isPlaying && this.queueStore.isPauseAllowed) {
|
||||
webapi.player_pause()
|
||||
player.pause()
|
||||
} else if (
|
||||
this.playerStore.isPlaying &&
|
||||
!this.queueStore.isPauseAllowed
|
||||
) {
|
||||
webapi.player_stop()
|
||||
player.stop()
|
||||
} else {
|
||||
webapi.player_play()
|
||||
player.play()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<a :disabled="disabled" @click="playPrevious">
|
||||
<a :disabled="disabled" @click="previous">
|
||||
<mdicon
|
||||
class="icon"
|
||||
name="skip-backward"
|
||||
@@ -9,8 +9,8 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import player from '@/api/player'
|
||||
import { useQueueStore } from '@/stores/queue'
|
||||
import webapi from '@/webapi'
|
||||
|
||||
export default {
|
||||
name: 'ControlPlayerPrevious',
|
||||
@@ -23,11 +23,8 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
playPrevious() {
|
||||
if (this.disabled) {
|
||||
return
|
||||
}
|
||||
webapi.player_previous()
|
||||
previous() {
|
||||
player.previous()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
<template>
|
||||
<a :class="{ 'is-dark': !playerStore.isRepeatOff }" @click="toggle">
|
||||
<button :class="{ 'is-dark': !playerStore.isRepeatOff }" @click="toggle">
|
||||
<mdicon
|
||||
class="icon"
|
||||
:name="icon"
|
||||
:size="16"
|
||||
:title="$t(`player.button.${icon}`)"
|
||||
/>
|
||||
</a>
|
||||
</button>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import player from '@/api/player'
|
||||
import { usePlayerStore } from '@/stores/player'
|
||||
import webapi from '@/webapi'
|
||||
|
||||
export default {
|
||||
name: 'ControlPlayerRepeat',
|
||||
@@ -31,11 +31,11 @@ export default {
|
||||
methods: {
|
||||
toggle() {
|
||||
if (this.playerStore.isRepeatAll) {
|
||||
webapi.player_repeat('single')
|
||||
player.repeat('single')
|
||||
} else if (this.playerStore.isRepeatSingle) {
|
||||
webapi.player_repeat('off')
|
||||
player.repeat('off')
|
||||
} else {
|
||||
webapi.player_repeat('all')
|
||||
player.repeat('all')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
<template>
|
||||
<a :class="{ 'is-dark': playerStore.shuffle }" @click="toggle">
|
||||
<button :class="{ 'is-dark': playerStore.shuffle }" @click="toggle">
|
||||
<mdicon
|
||||
class="icon"
|
||||
:name="icon"
|
||||
:size="16"
|
||||
:title="$t(`player.button.${icon}`)"
|
||||
/>
|
||||
</a>
|
||||
</button>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import player from '@/api/player'
|
||||
import { usePlayerStore } from '@/stores/player'
|
||||
import webapi from '@/webapi'
|
||||
|
||||
export default {
|
||||
name: 'ControlPlayerShuffle',
|
||||
@@ -28,7 +28,7 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
toggle() {
|
||||
webapi.player_shuffle(!this.playerStore.shuffle)
|
||||
player.shuffle(!this.playerStore.shuffle)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,8 +19,8 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import settings from '@/api/settings'
|
||||
import { useSettingsStore } from '@/stores/settings'
|
||||
import webapi from '@/webapi'
|
||||
|
||||
export default {
|
||||
name: 'ControlSetting',
|
||||
@@ -60,8 +60,8 @@ export default {
|
||||
name: this.name,
|
||||
value
|
||||
}
|
||||
webapi
|
||||
.settings_update(this.category, setting)
|
||||
settings
|
||||
.update(this.category, setting)
|
||||
.then(() => {
|
||||
window.clearTimeout(this.timerId)
|
||||
this.settingsStore.update(setting)
|
||||
|
||||
@@ -9,9 +9,7 @@
|
||||
<nav class="breadcrumb">
|
||||
<ul>
|
||||
<li v-for="directory in directories" :key="directory.index">
|
||||
<a @click="open(directory)">
|
||||
<span v-text="directory.name" />
|
||||
</a>
|
||||
<a @click="open(directory)" v-text="directory.name" />
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
@@ -46,8 +46,8 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import player from '@/api/player'
|
||||
import { usePlayerStore } from '@/stores/player'
|
||||
import webapi from '@/webapi'
|
||||
|
||||
export default {
|
||||
name: 'ListItemQueueItem',
|
||||
@@ -71,7 +71,7 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
play() {
|
||||
webapi.player_play({ item_id: this.item.id })
|
||||
player.play({ item_id: this.item.id })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
<script>
|
||||
import ListItem from '@/components/ListItem.vue'
|
||||
import ModalDialogTrack from '@/components/ModalDialogTrack.vue'
|
||||
import webapi from '@/webapi'
|
||||
import queue from '@/api/queue'
|
||||
|
||||
export default {
|
||||
name: 'ListTracks',
|
||||
@@ -44,15 +44,15 @@ export default {
|
||||
},
|
||||
open(item) {
|
||||
if (this.uris) {
|
||||
webapi.player_play_uri(this.uris, false, this.items.items.indexOf(item))
|
||||
queue.playUri(this.uris, false, this.items.items.indexOf(item))
|
||||
} else if (this.expression) {
|
||||
webapi.player_play_expression(
|
||||
queue.playExpression(
|
||||
this.expression,
|
||||
false,
|
||||
this.items.items.indexOf(item)
|
||||
)
|
||||
} else {
|
||||
webapi.player_play_uri(item.uri, false)
|
||||
queue.playUri(item.uri, false)
|
||||
}
|
||||
},
|
||||
openDetails(item) {
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
import ListItem from '@/components/ListItem.vue'
|
||||
import LoaderListItem from '@/components/LoaderListItem.vue'
|
||||
import ModalDialogTrackSpotify from '@/components/ModalDialogTrackSpotify.vue'
|
||||
import webapi from '@/webapi'
|
||||
import queue from '@/api/queue'
|
||||
|
||||
export default {
|
||||
name: 'ListTracksSpotify',
|
||||
@@ -48,11 +48,7 @@ export default {
|
||||
methods: {
|
||||
open(item) {
|
||||
if (item.is_playable) {
|
||||
webapi.player_play_uri(
|
||||
this.contextUri || item.uri,
|
||||
false,
|
||||
item.position || 0
|
||||
)
|
||||
queue.playUri(this.contextUri || item.uri, false, item.position || 0)
|
||||
}
|
||||
},
|
||||
openDetails(item) {
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
<script>
|
||||
import ControlUrlField from '@/components/ControlUrlField.vue'
|
||||
import ModalDialog from '@/components/ModalDialog.vue'
|
||||
import webapi from '@/webapi'
|
||||
import library from '@/api/library'
|
||||
|
||||
export default {
|
||||
name: 'ModalDialogAddRss',
|
||||
@@ -55,8 +55,8 @@ export default {
|
||||
methods: {
|
||||
add() {
|
||||
this.loading = true
|
||||
webapi
|
||||
.library_add(this.url)
|
||||
library
|
||||
.add(this.url)
|
||||
.then(() => {
|
||||
this.$emit('podcast-added')
|
||||
this.$emit('close')
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<script>
|
||||
import ControlUrlField from '@/components/ControlUrlField.vue'
|
||||
import ModalDialog from '@/components/ModalDialog.vue'
|
||||
import webapi from '@/webapi'
|
||||
import queue from '@/api/queue'
|
||||
|
||||
export default {
|
||||
name: 'ModalDialogAddStream',
|
||||
@@ -60,8 +60,8 @@ export default {
|
||||
methods: {
|
||||
add() {
|
||||
this.loading = true
|
||||
webapi
|
||||
.queue_add(this.url)
|
||||
queue
|
||||
.add(this.url)
|
||||
.then(() => {
|
||||
this.$emit('close')
|
||||
})
|
||||
@@ -79,8 +79,8 @@ export default {
|
||||
},
|
||||
play() {
|
||||
this.loading = true
|
||||
webapi
|
||||
.player_play_uri(this.url, false)
|
||||
queue
|
||||
.playUri(this.url, false)
|
||||
.then(() => {
|
||||
this.$emit('close')
|
||||
this.url = ''
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
<script>
|
||||
import ModalDialog from '@/components/ModalDialog.vue'
|
||||
import ModalDialogPlayable from '@/components/ModalDialogPlayable.vue'
|
||||
import webapi from '@/webapi'
|
||||
import library from '@/api/library'
|
||||
|
||||
export default {
|
||||
name: 'ModalDialogAlbum',
|
||||
@@ -60,7 +60,7 @@ export default {
|
||||
]
|
||||
},
|
||||
buttons() {
|
||||
if (this.media_kind_resolved === 'podcast') {
|
||||
if (this.mediaKindResolved === 'podcast') {
|
||||
if (this.item.data_kind === 'url') {
|
||||
return [
|
||||
{ handler: this.markAsPlayed, key: 'actions.mark-as-played' },
|
||||
@@ -74,7 +74,7 @@ export default {
|
||||
}
|
||||
return []
|
||||
},
|
||||
media_kind_resolved() {
|
||||
mediaKindResolved() {
|
||||
return this.mediaKind || this.item.media_kind
|
||||
},
|
||||
playable() {
|
||||
@@ -115,16 +115,14 @@ export default {
|
||||
this.showRemovePodcastModal = false
|
||||
},
|
||||
markAsPlayed() {
|
||||
webapi
|
||||
.library_album_track_update(this.item.id, { play_count: 'played' })
|
||||
.then(() => {
|
||||
this.$emit('play-count-changed')
|
||||
this.$emit('close')
|
||||
})
|
||||
library.updateAlbum(this.item.id, { play_count: 'played' }).then(() => {
|
||||
this.$emit('play-count-changed')
|
||||
this.$emit('close')
|
||||
})
|
||||
},
|
||||
openArtist() {
|
||||
this.$emit('close')
|
||||
if (this.media_kind_resolved === 'audiobook') {
|
||||
if (this.mediaKindResolved === 'audiobook') {
|
||||
this.$router.push({
|
||||
name: 'audiobooks-artist',
|
||||
params: { id: this.item.artist_id }
|
||||
@@ -142,10 +140,10 @@ export default {
|
||||
},
|
||||
removePodcast() {
|
||||
this.showRemovePodcastModal = false
|
||||
webapi.library_album_tracks(this.item.id, { limit: 1 }).then((album) => {
|
||||
webapi.library_track_playlists(album.items[0].id).then((data) => {
|
||||
library.albumTracks(this.item.id, { limit: 1 }).then((album) => {
|
||||
library.trackPlaylists(album.items[0].id).then((data) => {
|
||||
const { id } = data.items.find((item) => item.type === 'rss')
|
||||
webapi.library_playlist_delete(id).then(() => {
|
||||
library.playlistDelete(id).then(() => {
|
||||
this.$emit('podcast-deleted')
|
||||
this.$emit('close')
|
||||
})
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
import ControlButton from '@/components/ControlButton.vue'
|
||||
import ListProperties from '@/components/ListProperties.vue'
|
||||
import ModalDialog from '@/components/ModalDialog.vue'
|
||||
import webapi from '@/webapi'
|
||||
import queue from '@/api/queue'
|
||||
|
||||
export default {
|
||||
name: 'ModalDialogPlayable',
|
||||
@@ -53,25 +53,25 @@ export default {
|
||||
play() {
|
||||
this.$emit('close')
|
||||
if (this.item.expression) {
|
||||
webapi.player_play_expression(this.item.expression, false)
|
||||
queue.playExpression(this.item.expression, false)
|
||||
} else {
|
||||
webapi.player_play_uri(this.item.uris || this.item.uri, false)
|
||||
queue.playUri(this.item.uris || this.item.uri, false)
|
||||
}
|
||||
},
|
||||
addToQueue() {
|
||||
this.$emit('close')
|
||||
if (this.item.expression) {
|
||||
webapi.queue_expression_add(this.item.expression)
|
||||
queue.addExpression(this.item.expression)
|
||||
} else {
|
||||
webapi.queue_add(this.item.uris || this.item.uri)
|
||||
queue.addUri(this.item.uris || this.item.uri)
|
||||
}
|
||||
},
|
||||
addNextToQueue() {
|
||||
this.$emit('close')
|
||||
if (this.item.expression) {
|
||||
webapi.queue_expression_add_next(this.item.expression)
|
||||
queue.addExpression(this.item.expression, true)
|
||||
} else {
|
||||
webapi.queue_add_next(this.item.uris || this.item.uri)
|
||||
queue.addUri(this.item.uris || this.item.uri, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
|
||||
<script>
|
||||
import ModalDialog from '@/components/ModalDialog.vue'
|
||||
import webapi from '@/webapi'
|
||||
import queue from '@/api/queue'
|
||||
|
||||
export default {
|
||||
name: 'ModalDialogPlaylistSave',
|
||||
@@ -81,8 +81,8 @@ export default {
|
||||
},
|
||||
save() {
|
||||
this.loading = true
|
||||
webapi
|
||||
.queue_save_playlist(this.playlistName)
|
||||
queue
|
||||
.saveToPlaylist(this.playlistName)
|
||||
.then(() => {
|
||||
this.$emit('close')
|
||||
this.playlistName = ''
|
||||
|
||||
@@ -15,8 +15,9 @@
|
||||
import ListProperties from '@/components/ListProperties.vue'
|
||||
import ModalDialog from '@/components/ModalDialog.vue'
|
||||
import SpotifyWebApi from 'spotify-web-api-js'
|
||||
import player from '@/api/player'
|
||||
import queue from '@/api/queue'
|
||||
import { useServicesStore } from '@/stores/services'
|
||||
import webapi from '@/webapi'
|
||||
|
||||
export default {
|
||||
name: 'ModalDialogQueueItem',
|
||||
@@ -158,11 +159,11 @@ export default {
|
||||
},
|
||||
play() {
|
||||
this.$emit('close')
|
||||
webapi.player_play({ item_id: this.item.id })
|
||||
player.play({ item_id: this.item.id })
|
||||
},
|
||||
remove() {
|
||||
this.$emit('close')
|
||||
webapi.queue_remove(this.item.id)
|
||||
queue.remove(this.item.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
<script>
|
||||
import ControlPinField from '@/components/ControlPinField.vue'
|
||||
import ModalDialog from '@/components/ModalDialog.vue'
|
||||
import remotes from '@/api/remotes'
|
||||
import { useRemotesStore } from '@/stores/remotes'
|
||||
import webapi from '@/webapi'
|
||||
|
||||
export default {
|
||||
name: 'ModalDialogRemotePairing',
|
||||
@@ -59,7 +59,7 @@ export default {
|
||||
this.disabled = disabled
|
||||
},
|
||||
pair() {
|
||||
webapi.pairing_kickoff({ pin: this.pin }).then(() => {
|
||||
remotes.pair(this.pin).then(() => {
|
||||
this.pin = ''
|
||||
})
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
<script>
|
||||
import ModalDialogPlayable from '@/components/ModalDialogPlayable.vue'
|
||||
import webapi from '@/webapi'
|
||||
import library from '@/api/library'
|
||||
|
||||
export default {
|
||||
name: 'ModalDialogTrack',
|
||||
@@ -92,16 +92,14 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
markAsNew() {
|
||||
webapi
|
||||
.library_track_update(this.item.id, { play_count: 'reset' })
|
||||
.then(() => {
|
||||
this.$emit('play-count-changed')
|
||||
this.$emit('close')
|
||||
})
|
||||
library.updateTrack(this.item.id, { play_count: 'reset' }).then(() => {
|
||||
this.$emit('play-count-changed')
|
||||
this.$emit('close')
|
||||
})
|
||||
},
|
||||
markAsPlayed() {
|
||||
webapi
|
||||
.library_track_update(this.item.id, { play_count: 'increment' })
|
||||
library
|
||||
.updateTrack(this.item.id, { play_count: 'increment' })
|
||||
.then(() => {
|
||||
this.$emit('play-count-changed')
|
||||
this.$emit('close')
|
||||
|
||||
@@ -7,10 +7,7 @@
|
||||
>
|
||||
<template #content>
|
||||
<div v-if="!libraryStore.updating">
|
||||
<div
|
||||
v-if="servicesStore.isSpotifyActive || rss.tracks > 0"
|
||||
class="field"
|
||||
>
|
||||
<div v-if="servicesStore.isSpotifyActive" class="field">
|
||||
<label class="label" v-text="$t('dialog.update.info')" />
|
||||
<div class="control">
|
||||
<div class="select is-small">
|
||||
@@ -22,11 +19,7 @@
|
||||
value="spotify"
|
||||
v-text="$t('dialog.update.spotify')"
|
||||
/>
|
||||
<option
|
||||
v-if="rss.tracks > 0"
|
||||
value="rss"
|
||||
v-text="$t('dialog.update.feeds')"
|
||||
/>
|
||||
<option value="rss" v-text="$t('dialog.update.feeds')" />
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
@@ -47,9 +40,9 @@
|
||||
<script>
|
||||
import ControlSwitch from '@/components/ControlSwitch.vue'
|
||||
import ModalDialog from '@/components/ModalDialog.vue'
|
||||
import library from '@/api/library'
|
||||
import { useLibraryStore } from '@/stores/library'
|
||||
import { useServicesStore } from '@/stores/services'
|
||||
import webapi from '@/webapi'
|
||||
|
||||
export default {
|
||||
name: 'ModalDialogUpdate',
|
||||
@@ -80,17 +73,14 @@ export default {
|
||||
})
|
||||
}
|
||||
return actions
|
||||
},
|
||||
rss() {
|
||||
return this.libraryStore.rss
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
analyse() {
|
||||
if (this.rescanMetadata) {
|
||||
webapi.library_rescan(this.libraryStore.update_dialog_scan_kind)
|
||||
library.rescan(this.libraryStore.update_dialog_scan_kind)
|
||||
} else {
|
||||
webapi.library_update(this.libraryStore.update_dialog_scan_kind)
|
||||
library.update(this.libraryStore.update_dialog_scan_kind)
|
||||
}
|
||||
},
|
||||
cancel() {
|
||||
|
||||
@@ -383,8 +383,7 @@
|
||||
"connection-failed": "Fehler bei Verbindung zum OwnTone-Server",
|
||||
"request-failed": "Anfrage gescheitert (Status: {status} {cause} {url})",
|
||||
"queue-saved": "Warteschlange zu Playlist {name} gesichert",
|
||||
"appended-tracks": "{count} Track an die Abspielliste angehängt|{count} Tracks an die Abspielliste angehängt",
|
||||
"empty-queue": "Warteschlange ist leer"
|
||||
"appended-tracks": "{count} Track an die Abspielliste angehängt|{count} Tracks an die Abspielliste angehängt"
|
||||
},
|
||||
"grouped-list": {
|
||||
"today": "Heute",
|
||||
|
||||
@@ -383,8 +383,7 @@
|
||||
"connection-failed": "Failed to connect to OwnTone server",
|
||||
"request-failed": "Request failed (status: {status} {cause} {url})",
|
||||
"queue-saved": "Queue saved to playlist {name}",
|
||||
"appended-tracks": "{count} track appended to the queue|{count} tracks appended to the queue",
|
||||
"empty-queue": "Queue is empty"
|
||||
"appended-tracks": "{count} track appended to the queue|{count} tracks appended to the queue"
|
||||
},
|
||||
"grouped-list": {
|
||||
"today": "Today",
|
||||
|
||||
@@ -383,8 +383,7 @@
|
||||
"connection-failed": "Échec de connexion au serveur",
|
||||
"request-failed": "La requête a échoué (status: {status} {cause} {url})",
|
||||
"queue-saved": "La file d’attente enregistrée dans la liste de lecture {name}",
|
||||
"appended-tracks": "{count} piste ajoutée à la file d’attente|{count} pistes ajoutées à la file d’attente",
|
||||
"empty-queue": "La file d’attente est vide"
|
||||
"appended-tracks": "{count} piste ajoutée à la file d’attente|{count} pistes ajoutées à la file d’attente"
|
||||
},
|
||||
"grouped-list": {
|
||||
"today": "Aujourd’hui",
|
||||
|
||||
@@ -383,8 +383,7 @@
|
||||
"connection-failed": "无法连接到 OwnTone 服务器",
|
||||
"request-failed": "请求失败 (状态:{status} {cause} {url})",
|
||||
"queue-saved": "清单以添加到播放列表 {name}",
|
||||
"appended-tracks": "已附加到队列的 {count} 只曲目|已附加到队列的 {count} 只曲目",
|
||||
"empty-queue": "清单是空的"
|
||||
"appended-tracks": "已附加到队列的 {count} 只曲目|已附加到队列的 {count} 只曲目"
|
||||
},
|
||||
"grouped-list": {
|
||||
"today": "今日",
|
||||
|
||||
@@ -383,8 +383,7 @@
|
||||
"connection-failed": "無法連接到 OwnTone 伺服器",
|
||||
"request-failed": "請求失敗 (狀態:{status} {cause} {url})",
|
||||
"queue-saved": "清單以新增到播放列表 {name}",
|
||||
"appended-tracks": "已附加到隊列的 {count} 首曲目|已附加到隊列的 {count} 首曲目",
|
||||
"empty-queue": "清單是空的"
|
||||
"appended-tracks": "已附加到隊列的 {count} 首曲目|已附加到隊列的 {count} 首曲目"
|
||||
},
|
||||
"grouped-list": {
|
||||
"today": "今日",
|
||||
|
||||
@@ -29,7 +29,8 @@ import { GroupedList } from '@/lib/GroupedList'
|
||||
import HeadingHero from '@/components/HeadingHero.vue'
|
||||
import ListTracks from '@/components/ListTracks.vue'
|
||||
import ModalDialogAlbum from '@/components/ModalDialogAlbum.vue'
|
||||
import webapi from '@/webapi'
|
||||
import library from '@/api/library'
|
||||
import queue from '@/api/queue'
|
||||
|
||||
export default {
|
||||
name: 'PageAlbum',
|
||||
@@ -42,8 +43,8 @@ export default {
|
||||
},
|
||||
beforeRouteEnter(to, from, next) {
|
||||
Promise.all([
|
||||
webapi.library_album(to.params.id),
|
||||
webapi.library_album_tracks(to.params.id)
|
||||
library.album(to.params.id),
|
||||
library.albumTracks(to.params.id)
|
||||
]).then(([album, tracks]) => {
|
||||
next((vm) => {
|
||||
vm.album = album
|
||||
@@ -90,7 +91,7 @@ export default {
|
||||
this.showDetailsModal = true
|
||||
},
|
||||
play() {
|
||||
webapi.player_play_uri(this.album.uri, true)
|
||||
queue.playUri(this.album.uri, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,8 +29,9 @@ import HeadingHero from '@/components/HeadingHero.vue'
|
||||
import ListTracksSpotify from '@/components/ListTracksSpotify.vue'
|
||||
import ModalDialogAlbumSpotify from '@/components/ModalDialogAlbumSpotify.vue'
|
||||
import SpotifyWebApi from 'spotify-web-api-js'
|
||||
import queue from '@/api/queue'
|
||||
import services from '@/api/services'
|
||||
import { useServicesStore } from '@/stores/services'
|
||||
import webapi from '@/webapi'
|
||||
|
||||
export default {
|
||||
name: 'PageAlbumSpotify',
|
||||
@@ -43,7 +44,7 @@ export default {
|
||||
},
|
||||
beforeRouteEnter(to, from, next) {
|
||||
const spotifyApi = new SpotifyWebApi()
|
||||
webapi.spotify().then((data) => {
|
||||
services.spotify().then((data) => {
|
||||
spotifyApi.setAccessToken(data.webapi_token)
|
||||
spotifyApi
|
||||
.getAlbum(to.params.id, {
|
||||
@@ -98,7 +99,7 @@ export default {
|
||||
},
|
||||
play() {
|
||||
this.showDetailsModal = false
|
||||
webapi.player_play_uri(this.album.uri, true)
|
||||
queue.playUri(this.album.uri, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,9 +52,9 @@ import ListAlbums from '@/components/ListAlbums.vue'
|
||||
import ListIndexButtons from '@/components/ListIndexButtons.vue'
|
||||
import ListOptions from '@/components/ListOptions.vue'
|
||||
import TabsMusic from '@/components/TabsMusic.vue'
|
||||
import library from '@/api/library'
|
||||
import { useServicesStore } from '@/stores/services'
|
||||
import { useUIStore } from '@/stores/ui'
|
||||
import webapi from '@/webapi'
|
||||
|
||||
export default {
|
||||
name: 'PageAlbums',
|
||||
@@ -69,7 +69,7 @@ export default {
|
||||
TabsMusic
|
||||
},
|
||||
beforeRouteEnter(to, from, next) {
|
||||
webapi.library_albums('music').then((albums) => {
|
||||
library.albums('music').then((albums) => {
|
||||
next((vm) => {
|
||||
vm.albumList = new GroupedList(albums)
|
||||
})
|
||||
|
||||
@@ -55,9 +55,10 @@ import HeadingTitle from '@/components/HeadingTitle.vue'
|
||||
import ListAlbums from '@/components/ListAlbums.vue'
|
||||
import ListOptions from '@/components/ListOptions.vue'
|
||||
import ModalDialogArtist from '@/components/ModalDialogArtist.vue'
|
||||
import library from '@/api/library'
|
||||
import queue from '@/api/queue'
|
||||
import { useServicesStore } from '@/stores/services'
|
||||
import { useUIStore } from '@/stores/ui'
|
||||
import webapi from '@/webapi'
|
||||
|
||||
export default {
|
||||
name: 'PageArtist',
|
||||
@@ -73,8 +74,8 @@ export default {
|
||||
},
|
||||
beforeRouteEnter(to, from, next) {
|
||||
Promise.all([
|
||||
webapi.library_artist(to.params.id),
|
||||
webapi.library_artist_albums(to.params.id)
|
||||
library.artist(to.params.id),
|
||||
library.artistAlbums(to.params.id)
|
||||
]).then(([artist, albums]) => {
|
||||
next((vm) => {
|
||||
vm.artist = artist
|
||||
@@ -148,10 +149,7 @@ export default {
|
||||
})
|
||||
},
|
||||
play() {
|
||||
webapi.player_play_uri(
|
||||
this.albums.items.map((item) => item.uri).join(),
|
||||
true
|
||||
)
|
||||
queue.playUri(this.albums.items.map((item) => item.uri).join(), true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,8 +29,9 @@ import HeadingTitle from '@/components/HeadingTitle.vue'
|
||||
import ListAlbumsSpotify from '@/components/ListAlbumsSpotify.vue'
|
||||
import ModalDialogArtistSpotify from '@/components/ModalDialogArtistSpotify.vue'
|
||||
import SpotifyWebApi from 'spotify-web-api-js'
|
||||
import queue from '@/api/queue'
|
||||
import services from '@/api/services'
|
||||
import { useServicesStore } from '@/stores/services'
|
||||
import webapi from '@/webapi'
|
||||
|
||||
const PAGE_SIZE = 50
|
||||
|
||||
@@ -44,7 +45,7 @@ export default {
|
||||
ModalDialogArtistSpotify
|
||||
},
|
||||
beforeRouteEnter(to, from, next) {
|
||||
webapi.spotify().then((data) => {
|
||||
services.spotify().then((data) => {
|
||||
const spotifyApi = new SpotifyWebApi()
|
||||
spotifyApi.setAccessToken(data.webapi_token)
|
||||
Promise.all([
|
||||
@@ -95,7 +96,7 @@ export default {
|
||||
this.offset += data.limit
|
||||
},
|
||||
load({ loaded }) {
|
||||
webapi.spotify().then((data) => {
|
||||
api.spotify().then((data) => {
|
||||
const spotifyApi = new SpotifyWebApi()
|
||||
spotifyApi.setAccessToken(data.webapi_token)
|
||||
spotifyApi
|
||||
@@ -115,7 +116,7 @@ export default {
|
||||
},
|
||||
play() {
|
||||
this.showDetailsModal = false
|
||||
webapi.player_play_uri(this.artist.uri, true)
|
||||
queue.playUri(this.artist.uri, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,9 +57,10 @@ import ListIndexButtons from '@/components/ListIndexButtons.vue'
|
||||
import ListOptions from '@/components/ListOptions.vue'
|
||||
import ListTracks from '@/components/ListTracks.vue'
|
||||
import ModalDialogArtist from '@/components/ModalDialogArtist.vue'
|
||||
import library from '@/api/library'
|
||||
import queue from '@/api/queue'
|
||||
import { useServicesStore } from '@/stores/services'
|
||||
import { useUIStore } from '@/stores/ui'
|
||||
import webapi from '@/webapi'
|
||||
|
||||
export default {
|
||||
name: 'PageArtistTracks',
|
||||
@@ -76,8 +77,8 @@ export default {
|
||||
},
|
||||
beforeRouteEnter(to, from, next) {
|
||||
Promise.all([
|
||||
webapi.library_artist(to.params.id),
|
||||
webapi.library_artist_tracks(to.params.id)
|
||||
library.artist(to.params.id),
|
||||
library.artistTracks(to.params.id)
|
||||
]).then(([artist, tracks]) => {
|
||||
next((vm) => {
|
||||
vm.artist = artist
|
||||
@@ -158,10 +159,7 @@ export default {
|
||||
this.showDetailsModal = true
|
||||
},
|
||||
play() {
|
||||
webapi.player_play_uri(
|
||||
this.trackList.items.map((item) => item.uri).join(),
|
||||
true
|
||||
)
|
||||
queue.playUri(this.trackList.items.map((item) => item.uri).join(), true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,9 +52,9 @@ import ListArtists from '@/components/ListArtists.vue'
|
||||
import ListIndexButtons from '@/components/ListIndexButtons.vue'
|
||||
import ListOptions from '@/components/ListOptions.vue'
|
||||
import TabsMusic from '@/components/TabsMusic.vue'
|
||||
import library from '@/api/library'
|
||||
import { useServicesStore } from '@/stores/services'
|
||||
import { useUIStore } from '@/stores/ui'
|
||||
import webapi from '@/webapi'
|
||||
|
||||
export default {
|
||||
name: 'PageArtists',
|
||||
@@ -69,7 +69,7 @@ export default {
|
||||
TabsMusic
|
||||
},
|
||||
beforeRouteEnter(to, from, next) {
|
||||
webapi.library_artists('music').then((artists) => {
|
||||
library.artists('music').then((artists) => {
|
||||
next((vm) => {
|
||||
vm.artistList = new GroupedList(artists)
|
||||
})
|
||||
|
||||
@@ -30,7 +30,8 @@ import { GroupedList } from '@/lib/GroupedList'
|
||||
import HeadingHero from '@/components/HeadingHero.vue'
|
||||
import ListTracks from '@/components/ListTracks.vue'
|
||||
import ModalDialogAlbum from '@/components/ModalDialogAlbum.vue'
|
||||
import webapi from '@/webapi'
|
||||
import library from '@/api/library'
|
||||
import queue from '@/api/queue'
|
||||
|
||||
export default {
|
||||
name: 'PageAudiobooksAlbum',
|
||||
@@ -43,8 +44,8 @@ export default {
|
||||
},
|
||||
beforeRouteEnter(to, from, next) {
|
||||
Promise.all([
|
||||
webapi.library_album(to.params.id),
|
||||
webapi.library_album_tracks(to.params.id)
|
||||
library.album(to.params.id),
|
||||
library.albumTracks(to.params.id)
|
||||
]).then(([album, tracks]) => {
|
||||
next((vm) => {
|
||||
vm.album = album
|
||||
@@ -85,7 +86,7 @@ export default {
|
||||
this.showDetailsModal = true
|
||||
},
|
||||
play() {
|
||||
webapi.player_play_uri(this.album.uri, false)
|
||||
queue.playUri(this.album.uri, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ import HeadingTitle from '@/components/HeadingTitle.vue'
|
||||
import ListAlbums from '@/components/ListAlbums.vue'
|
||||
import ListIndexButtons from '@/components/ListIndexButtons.vue'
|
||||
import TabsAudiobooks from '@/components/TabsAudiobooks.vue'
|
||||
import webapi from '@/webapi'
|
||||
import library from '@/api/library'
|
||||
|
||||
export default {
|
||||
name: 'PageAudiobooksAlbums',
|
||||
@@ -32,7 +32,7 @@ export default {
|
||||
TabsAudiobooks
|
||||
},
|
||||
beforeRouteEnter(to, from, next) {
|
||||
webapi.library_albums('audiobook').then((albums) => {
|
||||
library.albums('audiobook').then((albums) => {
|
||||
next((vm) => {
|
||||
vm.albums = new GroupedList(albums, {
|
||||
index: { field: 'name_sort', type: String }
|
||||
|
||||
@@ -29,7 +29,8 @@ import { GroupedList } from '@/lib/GroupedList'
|
||||
import HeadingTitle from '@/components/HeadingTitle.vue'
|
||||
import ListAlbums from '@/components/ListAlbums.vue'
|
||||
import ModalDialogArtist from '@/components/ModalDialogArtist.vue'
|
||||
import webapi from '@/webapi'
|
||||
import library from '@/api/library'
|
||||
import queue from '@/api/queue'
|
||||
|
||||
export default {
|
||||
name: 'PageAudiobooksArtist',
|
||||
@@ -42,8 +43,8 @@ export default {
|
||||
},
|
||||
beforeRouteEnter(to, from, next) {
|
||||
Promise.all([
|
||||
webapi.library_artist(to.params.id),
|
||||
webapi.library_artist_albums(to.params.id)
|
||||
library.artist(to.params.id),
|
||||
library.artistAlbums(to.params.id)
|
||||
]).then(([artist, albums]) => {
|
||||
next((vm) => {
|
||||
vm.artist = artist
|
||||
@@ -76,10 +77,7 @@ export default {
|
||||
this.showDetailsModal = true
|
||||
},
|
||||
play() {
|
||||
webapi.player_play_uri(
|
||||
this.albums.items.map((item) => item.uri).join(),
|
||||
false
|
||||
)
|
||||
queue.playUri(this.albums.items.map((item) => item.uri).join(), false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ import HeadingTitle from '@/components/HeadingTitle.vue'
|
||||
import ListArtists from '@/components/ListArtists.vue'
|
||||
import ListIndexButtons from '@/components/ListIndexButtons.vue'
|
||||
import TabsAudiobooks from '@/components/TabsAudiobooks.vue'
|
||||
import webapi from '@/webapi'
|
||||
import library from '@/api/library'
|
||||
|
||||
export default {
|
||||
name: 'PageAudiobooksArtists',
|
||||
@@ -32,7 +32,7 @@ export default {
|
||||
TabsAudiobooks
|
||||
},
|
||||
beforeRouteEnter(to, from, next) {
|
||||
webapi.library_artists('audiobook').then((artists) => {
|
||||
library.artists('audiobook').then((artists) => {
|
||||
next((vm) => {
|
||||
vm.artists = new GroupedList(artists, {
|
||||
index: { field: 'name_sort', type: String }
|
||||
|
||||
@@ -20,7 +20,7 @@ import HeadingTitle from '@/components/HeadingTitle.vue'
|
||||
import ListGenres from '@/components/ListGenres.vue'
|
||||
import ListIndexButtons from '@/components/ListIndexButtons.vue'
|
||||
import TabsAudiobooks from '@/components/TabsAudiobooks.vue'
|
||||
import webapi from '@/webapi'
|
||||
import library from '@/api/library'
|
||||
|
||||
export default {
|
||||
name: 'PageAudiobooksGenres',
|
||||
@@ -32,7 +32,7 @@ export default {
|
||||
TabsAudiobooks
|
||||
},
|
||||
beforeRouteEnter(to, from, next) {
|
||||
webapi.library_genres('audiobook').then((genres) => {
|
||||
library.genres('audiobook').then((genres) => {
|
||||
next((vm) => {
|
||||
vm.genres = new GroupedList(genres, {
|
||||
index: { field: 'name_sort', type: String }
|
||||
|
||||
@@ -29,7 +29,8 @@ import { GroupedList } from '@/lib/GroupedList'
|
||||
import HeadingTitle from '@/components/HeadingTitle.vue'
|
||||
import ListAlbums from '@/components/ListAlbums.vue'
|
||||
import ModalDialogComposer from '@/components/ModalDialogComposer.vue'
|
||||
import webapi from '@/webapi'
|
||||
import library from '@/api/library'
|
||||
import queue from '@/api/queue'
|
||||
|
||||
export default {
|
||||
name: 'PageComposerAlbums',
|
||||
@@ -42,8 +43,8 @@ export default {
|
||||
},
|
||||
beforeRouteEnter(to, from, next) {
|
||||
Promise.all([
|
||||
webapi.library_composer(to.params.name),
|
||||
webapi.library_composer_albums(to.params.name)
|
||||
library.composer(to.params.name),
|
||||
library.composerAlbums(to.params.name)
|
||||
]).then(([composer, albums]) => {
|
||||
next((vm) => {
|
||||
vm.composer = composer
|
||||
@@ -90,7 +91,7 @@ export default {
|
||||
})
|
||||
},
|
||||
play() {
|
||||
webapi.player_play_expression(this.expression, true)
|
||||
queue.playExpression(this.expression, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,8 +43,9 @@ import ListIndexButtons from '@/components/ListIndexButtons.vue'
|
||||
import ListOptions from '@/components/ListOptions.vue'
|
||||
import ListTracks from '@/components/ListTracks.vue'
|
||||
import ModalDialogComposer from '@/components/ModalDialogComposer.vue'
|
||||
import library from '@/api/library'
|
||||
import queue from '@/api/queue'
|
||||
import { useUIStore } from '@/stores/ui'
|
||||
import webapi from '@/webapi'
|
||||
|
||||
export default {
|
||||
name: 'PageComposerTracks',
|
||||
@@ -60,8 +61,8 @@ export default {
|
||||
},
|
||||
beforeRouteEnter(to, from, next) {
|
||||
Promise.all([
|
||||
webapi.library_composer(to.params.name),
|
||||
webapi.library_composer_tracks(to.params.name)
|
||||
library.composer(to.params.name),
|
||||
library.composerTracks(to.params.name)
|
||||
]).then(([composer, tracks]) => {
|
||||
next((vm) => {
|
||||
vm.composer = composer
|
||||
@@ -134,7 +135,7 @@ export default {
|
||||
this.showDetailsModal = true
|
||||
},
|
||||
play() {
|
||||
webapi.player_play_expression(this.expression, true)
|
||||
queue.playExpression(this.expression, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ import HeadingTitle from '@/components/HeadingTitle.vue'
|
||||
import ListComposers from '@/components/ListComposers.vue'
|
||||
import ListIndexButtons from '@/components/ListIndexButtons.vue'
|
||||
import TabsMusic from '@/components/TabsMusic.vue'
|
||||
import webapi from '@/webapi'
|
||||
import library from '@/api/library'
|
||||
|
||||
export default {
|
||||
name: 'PageComposers',
|
||||
@@ -32,7 +32,7 @@ export default {
|
||||
TabsMusic
|
||||
},
|
||||
beforeRouteEnter(to, from, next) {
|
||||
webapi.library_composers('music').then((composers) => {
|
||||
library.composers('music').then((composers) => {
|
||||
next((vm) => {
|
||||
vm.composers = new GroupedList(composers, {
|
||||
index: { field: 'name_sort', type: String }
|
||||
|
||||
@@ -33,8 +33,10 @@ import ListDirectories from '@/components/ListDirectories.vue'
|
||||
import ListPlaylists from '@/components/ListPlaylists.vue'
|
||||
import ListTracks from '@/components/ListTracks.vue'
|
||||
import ModalDialogPlayable from '@/components/ModalDialogPlayable.vue'
|
||||
import configuration from '@/api/configuration'
|
||||
import library from '@/api/library'
|
||||
import queue from '@/api/queue'
|
||||
import { useConfigurationStore } from '@/stores/configuration'
|
||||
import webapi from '@/webapi'
|
||||
|
||||
export default {
|
||||
name: 'PageFiles',
|
||||
@@ -93,7 +95,7 @@ export default {
|
||||
methods: {
|
||||
async fetchData(to) {
|
||||
if (to.query.directory) {
|
||||
const data = await webapi.library_files(to.query.directory)
|
||||
const data = await library.files(to.query.directory)
|
||||
if (data) {
|
||||
this.directories = data.directories.map((directory) =>
|
||||
this.transform(directory.path)
|
||||
@@ -102,7 +104,7 @@ export default {
|
||||
this.tracks = new GroupedList(data.tracks)
|
||||
}
|
||||
} else {
|
||||
const config = await webapi.config()
|
||||
const config = await configuration.list()
|
||||
this.directories = config.directories.map((path) =>
|
||||
this.transform(path)
|
||||
)
|
||||
@@ -114,7 +116,7 @@ export default {
|
||||
this.showDetailsModal = true
|
||||
},
|
||||
play() {
|
||||
webapi.player_play_expression(this.expression, false)
|
||||
queue.playExpression(this.expression, false)
|
||||
},
|
||||
transform(path) {
|
||||
return { name: path.slice(path.lastIndexOf('/') + 1), path }
|
||||
|
||||
@@ -34,7 +34,8 @@ import HeadingTitle from '@/components/HeadingTitle.vue'
|
||||
import ListAlbums from '@/components/ListAlbums.vue'
|
||||
import ListIndexButtons from '@/components/ListIndexButtons.vue'
|
||||
import ModalDialogGenre from '@/components/ModalDialogGenre.vue'
|
||||
import webapi from '@/webapi'
|
||||
import library from '@/api/library'
|
||||
import queue from '@/api/queue'
|
||||
|
||||
export default {
|
||||
name: 'PageGenreAlbums',
|
||||
@@ -48,8 +49,8 @@ export default {
|
||||
},
|
||||
beforeRouteEnter(to, from, next) {
|
||||
Promise.all([
|
||||
webapi.library_genre(to.params.name, to.query.mediaKind),
|
||||
webapi.library_genre_albums(to.params.name, to.query.mediaKind)
|
||||
library.genre(to.params.name, to.query.mediaKind),
|
||||
library.genreAlbums(to.params.name, to.query.mediaKind)
|
||||
]).then(([genre, albums]) => {
|
||||
next((vm) => {
|
||||
vm.genre = genre.items.shift()
|
||||
@@ -98,7 +99,7 @@ export default {
|
||||
})
|
||||
},
|
||||
play() {
|
||||
webapi.player_play_expression(
|
||||
queue.playExpression(
|
||||
`genre is "${this.genre.name}" and media_kind is ${this.mediaKind}`,
|
||||
true
|
||||
)
|
||||
|
||||
@@ -44,8 +44,9 @@ import ListIndexButtons from '@/components/ListIndexButtons.vue'
|
||||
import ListOptions from '@/components/ListOptions.vue'
|
||||
import ListTracks from '@/components/ListTracks.vue'
|
||||
import ModalDialogGenre from '@/components/ModalDialogGenre.vue'
|
||||
import library from '@/api/library'
|
||||
import queue from '@/api/queue'
|
||||
import { useUIStore } from '@/stores/ui'
|
||||
import webapi from '@/webapi'
|
||||
|
||||
export default {
|
||||
name: 'PageGenreTracks',
|
||||
@@ -61,8 +62,8 @@ export default {
|
||||
},
|
||||
beforeRouteEnter(to, from, next) {
|
||||
Promise.all([
|
||||
webapi.library_genre(to.params.name, to.query.mediaKind),
|
||||
webapi.library_genre_tracks(to.params.name, to.query.mediaKind)
|
||||
library.genre(to.params.name, to.query.mediaKind),
|
||||
library.genreTracks(to.params.name, to.query.mediaKind)
|
||||
]).then(([genre, tracks]) => {
|
||||
next((vm) => {
|
||||
vm.genre = genre.items.shift()
|
||||
@@ -135,7 +136,7 @@ export default {
|
||||
})
|
||||
},
|
||||
play() {
|
||||
webapi.player_play_expression(this.expression, true)
|
||||
queue.playExpression(this.expression, true)
|
||||
},
|
||||
openDetails() {
|
||||
this.showDetailsModal = true
|
||||
|
||||
@@ -20,7 +20,7 @@ import HeadingTitle from '@/components/HeadingTitle.vue'
|
||||
import ListGenres from '@/components/ListGenres.vue'
|
||||
import ListIndexButtons from '@/components/ListIndexButtons.vue'
|
||||
import TabsMusic from '@/components/TabsMusic.vue'
|
||||
import webapi from '@/webapi'
|
||||
import library from '@/api/library'
|
||||
|
||||
export default {
|
||||
name: 'PageGenres',
|
||||
@@ -32,7 +32,7 @@ export default {
|
||||
TabsMusic
|
||||
},
|
||||
beforeRouteEnter(to, from, next) {
|
||||
webapi.library_genres('music').then((genres) => {
|
||||
library.genres('music').then((genres) => {
|
||||
next((vm) => {
|
||||
vm.genres = new GroupedList(genres, {
|
||||
index: { field: 'name_sort', type: String }
|
||||
|
||||
@@ -45,7 +45,7 @@ import HeadingTitle from '@/components/HeadingTitle.vue'
|
||||
import ListAlbums from '@/components/ListAlbums.vue'
|
||||
import ListTracks from '@/components/ListTracks.vue'
|
||||
import TabsMusic from '@/components/TabsMusic.vue'
|
||||
import webapi from '@/webapi'
|
||||
import library from '@/api/library'
|
||||
|
||||
export default {
|
||||
name: 'PageMusic',
|
||||
@@ -58,13 +58,13 @@ export default {
|
||||
},
|
||||
beforeRouteEnter(to, from, next) {
|
||||
Promise.all([
|
||||
webapi.search({
|
||||
library.search({
|
||||
expression:
|
||||
'time_added after 8 weeks ago and media_kind is music having track_count > 3 order by time_added desc',
|
||||
limit: 3,
|
||||
type: 'album'
|
||||
}),
|
||||
webapi.search({
|
||||
library.search({
|
||||
expression:
|
||||
'time_played after 8 weeks ago and media_kind is music order by time_played desc',
|
||||
limit: 3,
|
||||
|
||||
@@ -18,15 +18,15 @@ import { GroupedList } from '@/lib/GroupedList'
|
||||
import HeadingTitle from '@/components/HeadingTitle.vue'
|
||||
import ListAlbums from '@/components/ListAlbums.vue'
|
||||
import TabsMusic from '@/components/TabsMusic.vue'
|
||||
import library from '@/api/library'
|
||||
import { useSettingsStore } from '@/stores/settings'
|
||||
import webapi from '@/webapi'
|
||||
|
||||
export default {
|
||||
name: 'PageMusicRecentlyAdded',
|
||||
components: { ContentWithHeading, HeadingTitle, ListAlbums, TabsMusic },
|
||||
beforeRouteEnter(to, from, next) {
|
||||
const limit = useSettingsStore().recentlyAddedLimit
|
||||
webapi
|
||||
library
|
||||
.search({
|
||||
expression:
|
||||
'media_kind is music having track_count > 3 order by time_added desc',
|
||||
|
||||
@@ -18,13 +18,13 @@ import { GroupedList } from '@/lib/GroupedList'
|
||||
import HeadingTitle from '@/components/HeadingTitle.vue'
|
||||
import ListTracks from '@/components/ListTracks.vue'
|
||||
import TabsMusic from '@/components/TabsMusic.vue'
|
||||
import webapi from '@/webapi'
|
||||
import library from '@/api/library'
|
||||
|
||||
export default {
|
||||
name: 'PageMusicRecentlyPlayed',
|
||||
components: { ContentWithHeading, HeadingTitle, ListTracks, TabsMusic },
|
||||
beforeRouteEnter(to, from, next) {
|
||||
webapi
|
||||
library
|
||||
.search({
|
||||
expression:
|
||||
'time_played after 8 weeks ago and media_kind is music order by time_played desc',
|
||||
|
||||
@@ -45,7 +45,7 @@ import ListAlbumsSpotify from '@/components/ListAlbumsSpotify.vue'
|
||||
import ListPlaylistsSpotify from '@/components/ListPlaylistsSpotify.vue'
|
||||
import SpotifyWebApi from 'spotify-web-api-js'
|
||||
import TabsMusic from '@/components/TabsMusic.vue'
|
||||
import webapi from '@/webapi'
|
||||
import services from '@/api/services'
|
||||
|
||||
export default {
|
||||
name: 'PageMusicSpotify',
|
||||
@@ -57,7 +57,7 @@ export default {
|
||||
TabsMusic
|
||||
},
|
||||
beforeRouteEnter(to, from, next) {
|
||||
webapi.spotify().then((data) => {
|
||||
services.spotify().then((data) => {
|
||||
const spotifyApi = new SpotifyWebApi()
|
||||
spotifyApi.setAccessToken(data.webapi_token)
|
||||
Promise.all([
|
||||
|
||||
@@ -16,7 +16,7 @@ import HeadingTitle from '@/components/HeadingTitle.vue'
|
||||
import ListPlaylistsSpotify from '@/components/ListPlaylistsSpotify.vue'
|
||||
import SpotifyWebApi from 'spotify-web-api-js'
|
||||
import TabsMusic from '@/components/TabsMusic.vue'
|
||||
import webapi from '@/webapi'
|
||||
import services from '@/api/services'
|
||||
|
||||
export default {
|
||||
name: 'PageMusicSpotifyFeaturedPlaylists',
|
||||
@@ -27,7 +27,7 @@ export default {
|
||||
TabsMusic
|
||||
},
|
||||
beforeRouteEnter(to, from, next) {
|
||||
webapi.spotify().then((data) => {
|
||||
services.spotify().then((data) => {
|
||||
const spotifyApi = new SpotifyWebApi()
|
||||
spotifyApi.setAccessToken(data.webapi_token)
|
||||
spotifyApi
|
||||
|
||||
@@ -16,7 +16,7 @@ import HeadingTitle from '@/components/HeadingTitle.vue'
|
||||
import ListAlbumsSpotify from '@/components/ListAlbumsSpotify.vue'
|
||||
import SpotifyWebApi from 'spotify-web-api-js'
|
||||
import TabsMusic from '@/components/TabsMusic.vue'
|
||||
import webapi from '@/webapi'
|
||||
import services from '@/api/services'
|
||||
|
||||
export default {
|
||||
name: 'PageMusicSpotifyNewReleases',
|
||||
@@ -27,7 +27,7 @@ export default {
|
||||
TabsMusic
|
||||
},
|
||||
beforeRouteEnter(to, from, next) {
|
||||
webapi.spotify().then((data) => {
|
||||
services.spotify().then((data) => {
|
||||
const spotifyApi = new SpotifyWebApi()
|
||||
spotifyApi.setAccessToken(data.webapi_token)
|
||||
spotifyApi
|
||||
|
||||
@@ -55,11 +55,11 @@ import ControlImage from '@/components/ControlImage.vue'
|
||||
import ControlSlider from '@/components/ControlSlider.vue'
|
||||
import LyricsPane from '@/components/LyricsPane.vue'
|
||||
import ModalDialogQueueItem from '@/components/ModalDialogQueueItem.vue'
|
||||
import player from '@/api/player'
|
||||
import { useLyricsStore } from '@/stores/lyrics'
|
||||
import { usePlayerStore } from '@/stores/player'
|
||||
import { useQueueStore } from '@/stores/queue'
|
||||
import { useSettingsStore } from '@/stores/settings'
|
||||
import webapi from '@/webapi'
|
||||
|
||||
const INTERVAL = 1000
|
||||
|
||||
@@ -148,7 +148,7 @@ export default {
|
||||
}
|
||||
},
|
||||
created() {
|
||||
webapi.player_status().then((data) => {
|
||||
player.state().then((data) => {
|
||||
this.playerStore.$state = data
|
||||
if (this.playerStore.state === 'play') {
|
||||
this.intervalId = window.setInterval(this.tick, INTERVAL)
|
||||
@@ -171,7 +171,7 @@ export default {
|
||||
},
|
||||
seek() {
|
||||
if (!this.isLive) {
|
||||
webapi.player_seek_to_pos(this.trackProgress * INTERVAL)
|
||||
player.seekToPosition(this.trackProgress * INTERVAL)
|
||||
}
|
||||
},
|
||||
startDragging() {
|
||||
|
||||
@@ -14,8 +14,8 @@ import ContentWithHeading from '@/templates/ContentWithHeading.vue'
|
||||
import { GroupedList } from '@/lib/GroupedList'
|
||||
import HeadingTitle from '@/components/HeadingTitle.vue'
|
||||
import ListPlaylists from '@/components/ListPlaylists.vue'
|
||||
import library from '@/api/library'
|
||||
import { useConfigurationStore } from '@/stores/configuration'
|
||||
import webapi from '@/webapi'
|
||||
|
||||
export default {
|
||||
name: 'PagePlaylistFolder',
|
||||
@@ -63,8 +63,8 @@ export default {
|
||||
methods: {
|
||||
async fetchData(id) {
|
||||
const [playlist, playlistFolder] = await Promise.all([
|
||||
webapi.library_playlist(id),
|
||||
webapi.library_playlist_folder(id)
|
||||
library.playlist(id),
|
||||
library.playlistFolder(id)
|
||||
])
|
||||
this.playlist = playlist
|
||||
this.playlistList = new GroupedList(playlistFolder)
|
||||
|
||||
@@ -35,7 +35,8 @@ import { GroupedList } from '@/lib/GroupedList'
|
||||
import HeadingTitle from '@/components/HeadingTitle.vue'
|
||||
import ListTracks from '@/components/ListTracks.vue'
|
||||
import ModalDialogPlaylist from '@/components/ModalDialogPlaylist.vue'
|
||||
import webapi from '@/webapi'
|
||||
import library from '@/api/library'
|
||||
import queue from '@/api/queue'
|
||||
|
||||
export default {
|
||||
name: 'PagePlaylistTracks',
|
||||
@@ -48,8 +49,8 @@ export default {
|
||||
},
|
||||
beforeRouteEnter(to, from, next) {
|
||||
Promise.all([
|
||||
webapi.library_playlist(to.params.id),
|
||||
webapi.library_playlist_tracks(to.params.id)
|
||||
library.playlist(to.params.id),
|
||||
library.playlistTracks(to.params.id)
|
||||
]).then(([playlist, tracks]) => {
|
||||
next((vm) => {
|
||||
vm.playlist = playlist
|
||||
@@ -80,7 +81,7 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
play() {
|
||||
webapi.player_play_uri(this.uris, true)
|
||||
queue.playUri(this.uris, true)
|
||||
},
|
||||
openDetails() {
|
||||
this.showDetailsModal = true
|
||||
|
||||
@@ -39,8 +39,8 @@ import HeadingTitle from '@/components/HeadingTitle.vue'
|
||||
import ListTracksSpotify from '@/components/ListTracksSpotify.vue'
|
||||
import ModalDialogPlaylistSpotify from '@/components/ModalDialogPlaylistSpotify.vue'
|
||||
import SpotifyWebApi from 'spotify-web-api-js'
|
||||
import queue from '@/api/queue'
|
||||
import { useServicesStore } from '@/stores/services'
|
||||
import webapi from '@/webapi'
|
||||
|
||||
const PAGE_SIZE = 50
|
||||
|
||||
@@ -137,7 +137,7 @@ export default {
|
||||
},
|
||||
play() {
|
||||
this.showDetailsModal = false
|
||||
webapi.player_play_uri(this.playlist.uri, true)
|
||||
queue.playUri(this.playlist.uri, true)
|
||||
},
|
||||
openDetails() {
|
||||
this.showDetailsModal = true
|
||||
|
||||
@@ -36,7 +36,8 @@ import { GroupedList } from '@/lib/GroupedList'
|
||||
import HeadingHero from '@/components/HeadingHero.vue'
|
||||
import ListTracks from '@/components/ListTracks.vue'
|
||||
import ModalDialogAlbum from '@/components/ModalDialogAlbum.vue'
|
||||
import webapi from '@/webapi'
|
||||
import library from '@/api/library'
|
||||
import queue from '@/api/queue'
|
||||
|
||||
export default {
|
||||
name: 'PagePodcast',
|
||||
@@ -49,8 +50,8 @@ export default {
|
||||
},
|
||||
beforeRouteEnter(to, from, next) {
|
||||
Promise.all([
|
||||
webapi.library_album(to.params.id),
|
||||
webapi.library_podcast_episodes(to.params.id)
|
||||
library.album(to.params.id),
|
||||
library.podcastEpisodes(to.params.id)
|
||||
]).then(([album, tracks]) => {
|
||||
next((vm) => {
|
||||
vm.album = album
|
||||
@@ -80,10 +81,10 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
play() {
|
||||
webapi.player_play_uri(this.album.uri, false)
|
||||
queue.playUri(this.album.uri, false)
|
||||
},
|
||||
reloadTracks() {
|
||||
webapi.library_podcast_episodes(this.album.id).then((tracks) => {
|
||||
library.podcastEpisodes(this.album.id).then((tracks) => {
|
||||
this.tracks = new GroupedList(tracks)
|
||||
})
|
||||
},
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<content-with-heading v-if="tracks.items.length > 0">
|
||||
<content-with-heading v-if="episodes.items.length > 0">
|
||||
<template #heading>
|
||||
<heading-title :content="{ title: $t('page.podcasts.new-episodes') }" />
|
||||
</template>
|
||||
@@ -14,9 +14,9 @@
|
||||
</template>
|
||||
<template #content>
|
||||
<list-tracks
|
||||
:items="tracks"
|
||||
:items="episodes"
|
||||
:show-progress="true"
|
||||
@play-count-changed="reloadNewEpisodes"
|
||||
@play-count-changed="reloadEpisodes"
|
||||
/>
|
||||
</template>
|
||||
</content-with-heading>
|
||||
@@ -26,7 +26,7 @@
|
||||
</template>
|
||||
<template #actions>
|
||||
<control-button
|
||||
v-if="libraryStore.rss"
|
||||
v-if="hasRss"
|
||||
:button="{
|
||||
handler: updateRss,
|
||||
icon: 'refresh',
|
||||
@@ -44,7 +44,7 @@
|
||||
<template #content>
|
||||
<list-albums
|
||||
:items="albums"
|
||||
@play-count-changed="reloadNewEpisodes"
|
||||
@play-count-changed="reloadEpisodes"
|
||||
@podcast-deleted="reloadPodcasts"
|
||||
/>
|
||||
</template>
|
||||
@@ -64,9 +64,9 @@ import HeadingTitle from '@/components/HeadingTitle.vue'
|
||||
import ListAlbums from '@/components/ListAlbums.vue'
|
||||
import ListTracks from '@/components/ListTracks.vue'
|
||||
import ModalDialogAddRss from '@/components/ModalDialogAddRss.vue'
|
||||
import library from '@/api/library'
|
||||
import { useLibraryStore } from '@/stores/library'
|
||||
import { useUIStore } from '@/stores/ui'
|
||||
import webapi from '@/webapi'
|
||||
|
||||
export default {
|
||||
name: 'PagePodcasts',
|
||||
@@ -80,12 +80,14 @@ export default {
|
||||
},
|
||||
beforeRouteEnter(to, from, next) {
|
||||
Promise.all([
|
||||
webapi.library_albums('podcast'),
|
||||
webapi.library_podcasts_new_episodes()
|
||||
]).then(([albums, tracks]) => {
|
||||
library.albums('podcast'),
|
||||
library.newPodcastEpisodes(),
|
||||
library.rssCount()
|
||||
]).then(([albums, episodes, rssCount]) => {
|
||||
next((vm) => {
|
||||
vm.albums = new GroupedList(albums)
|
||||
vm.tracks = new GroupedList(tracks)
|
||||
vm.episodes = new GroupedList(episodes)
|
||||
vm.rssCount = rssCount
|
||||
})
|
||||
})
|
||||
},
|
||||
@@ -95,11 +97,15 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
albums: [],
|
||||
showAddPodcastModal: false,
|
||||
tracks: { items: [] }
|
||||
episodes: { items: [] },
|
||||
rssCount: {},
|
||||
showAddPodcastModal: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
hasRss() {
|
||||
return (this.rssCount.albums ?? 0) > 0
|
||||
},
|
||||
heading() {
|
||||
if (this.albums.total) {
|
||||
return {
|
||||
@@ -112,23 +118,29 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
markAllAsPlayed() {
|
||||
this.tracks.items.forEach((ep) => {
|
||||
webapi.library_track_update(ep.id, { play_count: 'increment' })
|
||||
this.episodes.items.forEach((episode) => {
|
||||
library.updateTrack(episode.id, { play_count: 'increment' })
|
||||
})
|
||||
this.tracks.items = {}
|
||||
this.episodes.items = {}
|
||||
},
|
||||
openAddPodcastDialog() {
|
||||
this.showAddPodcastModal = true
|
||||
},
|
||||
reloadNewEpisodes() {
|
||||
webapi.library_podcasts_new_episodes().then((tracks) => {
|
||||
this.tracks = new GroupedList(tracks)
|
||||
reloadEpisodes() {
|
||||
library.newPodcastEpisodes().then((episodes) => {
|
||||
this.episodes = new GroupedList(episodes)
|
||||
})
|
||||
},
|
||||
reloadPodcasts() {
|
||||
webapi.library_albums('podcast').then((albums) => {
|
||||
library.albums('podcast').then((albums) => {
|
||||
this.albums = new GroupedList(albums)
|
||||
this.reloadNewEpisodes()
|
||||
this.reloadEpisodes()
|
||||
this.reloadRssCount()
|
||||
})
|
||||
},
|
||||
reloadRssCount() {
|
||||
library.rssCount().then((rssCount) => {
|
||||
this.rssCount = rssCount
|
||||
})
|
||||
},
|
||||
updateRss() {
|
||||
|
||||
@@ -101,11 +101,11 @@ import ModalDialogAddStream from '@/components/ModalDialogAddStream.vue'
|
||||
import ModalDialogPlaylistSave from '@/components/ModalDialogPlaylistSave.vue'
|
||||
import ModalDialogQueueItem from '@/components/ModalDialogQueueItem.vue'
|
||||
import draggable from 'vuedraggable'
|
||||
import queue from '@/api/queue'
|
||||
import { useConfigurationStore } from '@/stores/configuration'
|
||||
import { usePlayerStore } from '@/stores/player'
|
||||
import { useQueueStore } from '@/stores/queue'
|
||||
import { useUIStore } from '@/stores/ui'
|
||||
import webapi from '@/webapi'
|
||||
|
||||
export default {
|
||||
name: 'PageQueue',
|
||||
@@ -157,7 +157,7 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
clearQueue() {
|
||||
webapi.queue_clear()
|
||||
queue.clear()
|
||||
},
|
||||
isRemovable(item) {
|
||||
return item.id !== this.playerStore.item_id && this.editing
|
||||
@@ -168,7 +168,7 @@ export default {
|
||||
const item = this.items[oldPosition]
|
||||
const newPosition = item.position + (event.newIndex - event.oldIndex)
|
||||
if (newPosition !== oldPosition) {
|
||||
webapi.queue_move(item.id, newPosition)
|
||||
queue.move(item.id, newPosition)
|
||||
}
|
||||
},
|
||||
openAddStreamDialog() {
|
||||
@@ -184,7 +184,7 @@ export default {
|
||||
}
|
||||
},
|
||||
remove(item) {
|
||||
webapi.queue_remove(item.id)
|
||||
queue.remove(item.id)
|
||||
},
|
||||
toggleEdit() {
|
||||
this.editing = !this.editing
|
||||
|
||||
@@ -18,7 +18,7 @@ import { GroupedList } from '@/lib/GroupedList'
|
||||
import HeadingTitle from '@/components/HeadingTitle.vue'
|
||||
import ListIndexButtons from '@/components/ListIndexButtons.vue'
|
||||
import ListTracks from '@/components/ListTracks.vue'
|
||||
import webapi from '@/webapi'
|
||||
import library from '@/api/library'
|
||||
|
||||
export default {
|
||||
name: 'PageRadioStreams',
|
||||
@@ -29,7 +29,7 @@ export default {
|
||||
ListTracks
|
||||
},
|
||||
beforeRouteEnter(to, from, next) {
|
||||
webapi.library_radio_streams().then((tracks) => {
|
||||
library.radioStreams().then((tracks) => {
|
||||
next((vm) => {
|
||||
vm.tracks = new GroupedList(tracks, {
|
||||
index: { field: 'title_sort', type: String }
|
||||
|
||||
@@ -84,8 +84,8 @@ import ListComposers from '@/components/ListComposers.vue'
|
||||
import ListPlaylists from '@/components/ListPlaylists.vue'
|
||||
import ListTracks from '@/components/ListTracks.vue'
|
||||
import TabsSearch from '@/components/TabsSearch.vue'
|
||||
import library from '@/api/library'
|
||||
import { useSearchStore } from '@/stores/search'
|
||||
import webapi from '@/webapi'
|
||||
|
||||
const PAGE_SIZE = 3,
|
||||
SEARCH_TYPES = [
|
||||
@@ -190,7 +190,7 @@ export default {
|
||||
} else {
|
||||
parameters.expression = `(album includes "${this.searchStore.query}" or artist includes "${this.searchStore.query}") and media_kind is ${kind}`
|
||||
}
|
||||
webapi.search(parameters).then((data) => {
|
||||
library.search(parameters).then((data) => {
|
||||
this.results.set(type, new GroupedList(data[`${parameters.type}s`]))
|
||||
})
|
||||
},
|
||||
|
||||
@@ -71,8 +71,8 @@ import ListPlaylistsSpotify from '@/components/ListPlaylistsSpotify.vue'
|
||||
import ListTracksSpotify from '@/components/ListTracksSpotify.vue'
|
||||
import SpotifyWebApi from 'spotify-web-api-js'
|
||||
import TabsSearch from '@/components/TabsSearch.vue'
|
||||
import services from '@/api/services'
|
||||
import { useSearchStore } from '@/stores/search'
|
||||
import webapi from '@/webapi'
|
||||
|
||||
const PAGE_SIZE = 3,
|
||||
PAGE_SIZE_EXPANDED = 50,
|
||||
@@ -158,7 +158,7 @@ export default {
|
||||
}
|
||||
},
|
||||
searchItems() {
|
||||
return webapi.spotify().then((data) => {
|
||||
return services.spotify().then((data) => {
|
||||
this.parameters.market = data.webapi_country
|
||||
const spotifyApi = new SpotifyWebApi()
|
||||
spotifyApi.setAccessToken(data.webapi_token)
|
||||
|
||||
@@ -40,7 +40,11 @@
|
||||
class="content"
|
||||
v-text="$t('page.settings.devices.speaker-pairing-info')"
|
||||
/>
|
||||
<div v-for="output in outputs" :key="output.id" class="field is-grouped">
|
||||
<div
|
||||
v-for="output in outputsStore.outputs"
|
||||
:key="output.id"
|
||||
class="field is-grouped"
|
||||
>
|
||||
<control-switch
|
||||
v-model="output.selected"
|
||||
@update:model-value="toggleOutput(output.id)"
|
||||
@@ -77,9 +81,9 @@ import ControlPinField from '@/components/ControlPinField.vue'
|
||||
import ControlSwitch from '@/components/ControlSwitch.vue'
|
||||
import HeadingTitle from '@/components/HeadingTitle.vue'
|
||||
import TabsSettings from '@/components/TabsSettings.vue'
|
||||
import outputs from '@/api/outputs'
|
||||
import { useOutputsStore } from '@/stores/outputs'
|
||||
import { useRemotesStore } from '@/stores/remotes'
|
||||
import webapi from '@/webapi'
|
||||
|
||||
export default {
|
||||
name: 'PageSettingsDevices',
|
||||
@@ -100,17 +104,12 @@ export default {
|
||||
remotePin: ''
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
outputs() {
|
||||
return this.outputsStore.outputs
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
pairRemote() {
|
||||
webapi.pairing_kickoff({ pin: this.remotePin })
|
||||
remotes.pair(this.remotePin)
|
||||
},
|
||||
pairOutput(identifier) {
|
||||
webapi.output_update(identifier, { pin: this.outputPin })
|
||||
outputs.update(identifier, { pin: this.outputPin })
|
||||
},
|
||||
onRemotePinChange(pin, disabled) {
|
||||
this.remotePin = pin
|
||||
@@ -120,7 +119,7 @@ export default {
|
||||
this.outputPin = pin
|
||||
},
|
||||
toggleOutput(identifier) {
|
||||
webapi.output_toggle(identifier)
|
||||
outputs.toggle(identifier)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,23 +73,28 @@
|
||||
<div class="field is-grouped">
|
||||
<div class="control">
|
||||
<input
|
||||
v-model="lastfm_login.user"
|
||||
v-model="lastfmCredentials.user"
|
||||
class="input"
|
||||
type="text"
|
||||
:placeholder="$t('page.settings.services.username')"
|
||||
/>
|
||||
<div class="help is-danger" v-text="lastfm_login.errors.user" />
|
||||
<div
|
||||
v-if="lastfmErrors"
|
||||
class="help is-danger"
|
||||
v-text="lastfmErrors.user"
|
||||
/>
|
||||
</div>
|
||||
<div class="control">
|
||||
<input
|
||||
v-model="lastfm_login.password"
|
||||
v-model="lastfmCredentials.password"
|
||||
class="input"
|
||||
type="password"
|
||||
:placeholder="$t('page.settings.services.password')"
|
||||
/>
|
||||
<div
|
||||
v-if="lastfmErrors"
|
||||
class="help is-danger"
|
||||
v-text="lastfm_login.errors.password"
|
||||
v-text="lastfmErrors.password"
|
||||
/>
|
||||
</div>
|
||||
<div class="control">
|
||||
@@ -100,7 +105,11 @@
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="help is-danger" v-text="lastfm_login.errors.error" />
|
||||
<div
|
||||
v-if="lastfmErrors"
|
||||
class="help is-danger"
|
||||
v-text="lastfmErrors.error"
|
||||
/>
|
||||
</form>
|
||||
</div>
|
||||
<div v-else>
|
||||
@@ -120,8 +129,8 @@
|
||||
import ContentWithHeading from '@/templates/ContentWithHeading.vue'
|
||||
import HeadingTitle from '@/components/HeadingTitle.vue'
|
||||
import TabsSettings from '@/components/TabsSettings.vue'
|
||||
import services from '@/api/services'
|
||||
import { useServicesStore } from '@/stores/services'
|
||||
import webapi from '@/webapi'
|
||||
|
||||
export default {
|
||||
name: 'PageSettingsOnlineServices',
|
||||
@@ -131,33 +140,25 @@ export default {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
lastfm_login: {
|
||||
errors: { error: '', password: '', user: '' },
|
||||
password: '',
|
||||
user: ''
|
||||
}
|
||||
lastfmCredentials: { password: '', user: '' },
|
||||
lastfmErrors: { error: '', password: '', user: '' }
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
loginLastfm() {
|
||||
webapi.lastfm_login(this.lastfm_login).then((data) => {
|
||||
this.lastfm_login.user = ''
|
||||
this.lastfm_login.password = ''
|
||||
this.lastfm_login.errors.user = ''
|
||||
this.lastfm_login.errors.password = ''
|
||||
this.lastfm_login.errors.error = ''
|
||||
if (!data.success) {
|
||||
this.lastfm_login.errors.user = data.errors.user
|
||||
this.lastfm_login.errors.password = data.errors.password
|
||||
this.lastfm_login.errors.error = data.errors.error
|
||||
services.loginLastfm(this.lastfmCredentials).then((data) => {
|
||||
this.lastfmErrors = data.errors
|
||||
this.lastfmCredentials.password = ''
|
||||
if (data.success) {
|
||||
this.lastfmCredentials.user = ''
|
||||
}
|
||||
})
|
||||
},
|
||||
logoutLastfm() {
|
||||
webapi.lastfm_logout()
|
||||
services.logoutLastfm()
|
||||
},
|
||||
logoutSpotify() {
|
||||
webapi.spotify_logout()
|
||||
services.logoutSpotify()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import library from '@/api/library'
|
||||
|
||||
export const useLibraryStore = defineStore('LibraryStore', {
|
||||
actions: {
|
||||
async initialise() {
|
||||
this.$state = await library.state()
|
||||
}
|
||||
},
|
||||
state: () => ({
|
||||
albums: 0,
|
||||
artists: 0,
|
||||
db_playtime: 0,
|
||||
rss: {},
|
||||
songs: 0,
|
||||
started_at: '01',
|
||||
update_dialog_scan_kind: '',
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import outputs from '@/api/outputs'
|
||||
|
||||
export const useOutputsStore = defineStore('OutputsStore', {
|
||||
actions: {
|
||||
async initialise() {
|
||||
this.$state = await outputs.state()
|
||||
}
|
||||
},
|
||||
state: () => ({
|
||||
outputs: []
|
||||
})
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import player from '@/api/player'
|
||||
|
||||
export const usePlayerStore = defineStore('PlayerStore', {
|
||||
actions: {
|
||||
async initialise() {
|
||||
this.$state = await player.state()
|
||||
}
|
||||
},
|
||||
getters: {
|
||||
isPlaying: (state) => state.state === 'play',
|
||||
isRepeatAll: (state) => state.repeat === 'all',
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import queue from '@/api/queue'
|
||||
import { useConfigurationStore } from '@/stores/configuration'
|
||||
import { usePlayerStore } from '@/stores/player'
|
||||
|
||||
export const useQueueStore = defineStore('QueueStore', {
|
||||
actions: {
|
||||
async initialise() {
|
||||
this.$state = await queue.state()
|
||||
}
|
||||
},
|
||||
getters: {
|
||||
current(state) {
|
||||
const player = usePlayerStore()
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import remotes from '@/api/remotes'
|
||||
|
||||
export const useRemotesStore = defineStore('RemotesStore', {
|
||||
actions: {
|
||||
async initialise() {
|
||||
this.$state = await remotes.state()
|
||||
}
|
||||
},
|
||||
state: () => ({
|
||||
active: false,
|
||||
remote: ''
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import i18n from '@/i18n'
|
||||
import settings from '@/api/settings'
|
||||
|
||||
const { t, availableLocales } = i18n.global
|
||||
|
||||
@@ -12,6 +13,9 @@ export const useSettingsStore = defineStore('SettingsStore', {
|
||||
?.options.find((option) => option.name === optionName) ?? {}
|
||||
)
|
||||
},
|
||||
async initialise() {
|
||||
this.$state = await settings.state()
|
||||
},
|
||||
update(option) {
|
||||
const settingCategory = this.categories.find(
|
||||
(category) => category.name === option.category
|
||||
|
||||
@@ -1,427 +0,0 @@
|
||||
import axios from 'axios'
|
||||
import i18n from '@/i18n'
|
||||
import { useNotificationsStore } from '@/stores/notifications'
|
||||
import { useQueueStore } from '@/stores/queue'
|
||||
|
||||
const { t } = i18n.global
|
||||
|
||||
axios.interceptors.response.use(
|
||||
(response) => response.data,
|
||||
(error) => {
|
||||
if (error.request.status && error.request.responseURL) {
|
||||
useNotificationsStore().add({
|
||||
text: t('server.request-failed', {
|
||||
cause: error.request.statusText,
|
||||
status: error.request.status,
|
||||
url: error.request.responseURL
|
||||
}),
|
||||
type: 'danger'
|
||||
})
|
||||
}
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
|
||||
export default {
|
||||
config() {
|
||||
return axios.get('./api/config')
|
||||
},
|
||||
|
||||
lastfm() {
|
||||
return axios.get('./api/lastfm')
|
||||
},
|
||||
|
||||
lastfm_login(credentials) {
|
||||
return axios.post('./api/lastfm-login', credentials)
|
||||
},
|
||||
|
||||
lastfm_logout() {
|
||||
return axios.get('./api/lastfm-logout')
|
||||
},
|
||||
|
||||
library_add(url) {
|
||||
return axios.post('./api/library/add', null, { params: { url } })
|
||||
},
|
||||
|
||||
library_album(albumId) {
|
||||
return axios.get(`./api/library/albums/${albumId}`)
|
||||
},
|
||||
|
||||
library_album_track_update(albumId, attributes) {
|
||||
return axios.put(`./api/library/albums/${albumId}/tracks`, null, {
|
||||
params: attributes
|
||||
})
|
||||
},
|
||||
|
||||
library_album_tracks(albumId, filter = { limit: -1, offset: 0 }) {
|
||||
return axios.get(`./api/library/albums/${albumId}/tracks`, {
|
||||
params: filter
|
||||
})
|
||||
},
|
||||
|
||||
library_albums(mediaKind) {
|
||||
return axios.get('./api/library/albums', { params: { mediaKind } })
|
||||
},
|
||||
|
||||
library_artist(artistId) {
|
||||
return axios.get(`./api/library/artists/${artistId}`)
|
||||
},
|
||||
|
||||
library_artist_albums(artistId) {
|
||||
return axios.get(`./api/library/artists/${artistId}/albums`)
|
||||
},
|
||||
|
||||
async library_artist_tracks(artist) {
|
||||
const params = {
|
||||
expression: `songartistid is "${artist}"`,
|
||||
type: 'tracks'
|
||||
}
|
||||
const data = await axios.get('./api/search', { params })
|
||||
return data.tracks
|
||||
},
|
||||
|
||||
library_artists(mediaKind) {
|
||||
return axios.get('./api/library/artists', { params: { mediaKind } })
|
||||
},
|
||||
|
||||
library_composer(composer) {
|
||||
return axios.get(`./api/library/composers/${encodeURIComponent(composer)}`)
|
||||
},
|
||||
|
||||
async library_composer_albums(composer) {
|
||||
const params = {
|
||||
expression: `composer is "${composer}" and media_kind is music`,
|
||||
type: 'albums'
|
||||
}
|
||||
const data = await axios.get('./api/search', { params })
|
||||
return data.albums
|
||||
},
|
||||
|
||||
async library_composer_tracks(composer) {
|
||||
const params = {
|
||||
expression: `composer is "${composer}" and media_kind is music`,
|
||||
type: 'tracks'
|
||||
}
|
||||
const data = await axios.get('./api/search', { params })
|
||||
return data.tracks
|
||||
},
|
||||
|
||||
library_composers(mediaKind) {
|
||||
return axios.get('./api/library/composers', { params: { mediaKind } })
|
||||
},
|
||||
|
||||
library_count(expression) {
|
||||
return axios.get(`./api/library/count?expression=${expression}`)
|
||||
},
|
||||
|
||||
library_files(directory) {
|
||||
return axios.get('./api/library/files', { params: { directory } })
|
||||
},
|
||||
|
||||
async library_genre(genre, mediaKind) {
|
||||
const params = {
|
||||
expression: `genre is "${genre}" and media_kind is ${mediaKind}`,
|
||||
type: 'genres'
|
||||
}
|
||||
const data = await axios.get('./api/search', { params })
|
||||
return data.genres
|
||||
},
|
||||
|
||||
async library_genre_albums(genre, mediaKind) {
|
||||
const params = {
|
||||
expression: `genre is "${genre}" and media_kind is ${mediaKind}`,
|
||||
type: 'albums'
|
||||
}
|
||||
const data = await axios.get('./api/search', { params })
|
||||
return data.albums
|
||||
},
|
||||
|
||||
async library_genre_tracks(genre, mediaKind) {
|
||||
const params = {
|
||||
expression: `genre is "${genre}" and media_kind is ${mediaKind}`,
|
||||
type: 'tracks'
|
||||
}
|
||||
const data = await axios.get('./api/search', { params })
|
||||
return data.tracks
|
||||
},
|
||||
|
||||
async library_genres(mediaKind) {
|
||||
const params = {
|
||||
expression: `media_kind is ${mediaKind}`,
|
||||
type: 'genres'
|
||||
}
|
||||
const data = await axios.get('./api/search', { params })
|
||||
return data.genres
|
||||
},
|
||||
|
||||
library_playlist(playlistId) {
|
||||
return axios.get(`./api/library/playlists/${playlistId}`)
|
||||
},
|
||||
|
||||
library_playlist_delete(playlistId) {
|
||||
return axios.delete(`./api/library/playlists/${playlistId}`)
|
||||
},
|
||||
|
||||
library_playlist_folder(playlistId = 0) {
|
||||
return axios.get(`./api/library/playlists/${playlistId}/playlists`)
|
||||
},
|
||||
|
||||
library_playlist_tracks(playlistId) {
|
||||
return axios.get(`./api/library/playlists/${playlistId}/tracks`)
|
||||
},
|
||||
|
||||
async library_podcast_episodes(albumId) {
|
||||
const params = {
|
||||
expression: `media_kind is podcast and songalbumid is "${albumId}" ORDER BY date_released DESC`,
|
||||
type: 'tracks'
|
||||
}
|
||||
const data = await axios.get('./api/search', { params })
|
||||
return data.tracks
|
||||
},
|
||||
|
||||
async library_podcasts_new_episodes() {
|
||||
const params = {
|
||||
expression:
|
||||
'media_kind is podcast and play_count = 0 ORDER BY time_added DESC',
|
||||
type: 'tracks'
|
||||
}
|
||||
const data = await axios.get('./api/search', { params })
|
||||
return data.tracks
|
||||
},
|
||||
|
||||
async library_radio_streams() {
|
||||
const params = {
|
||||
expression: 'data_kind is url and song_length = 0',
|
||||
media_kind: 'music',
|
||||
type: 'tracks'
|
||||
}
|
||||
const data = await axios.get('./api/search', { params })
|
||||
return data.tracks
|
||||
},
|
||||
|
||||
library_rescan(scanKind) {
|
||||
return axios.put('./api/rescan', null, { params: { scanKind } })
|
||||
},
|
||||
|
||||
library_stats() {
|
||||
return axios.get('./api/library')
|
||||
},
|
||||
|
||||
library_track(trackId) {
|
||||
return axios.get(`./api/library/tracks/${trackId}`)
|
||||
},
|
||||
|
||||
library_track_playlists(trackId) {
|
||||
return axios.get(`./api/library/tracks/${trackId}/playlists`)
|
||||
},
|
||||
|
||||
library_track_update(trackId, attributes = {}) {
|
||||
return axios.put(`./api/library/tracks/${trackId}`, null, {
|
||||
params: attributes
|
||||
})
|
||||
},
|
||||
|
||||
library_update(scanKind) {
|
||||
return axios.put('./api/update', null, { params: { scanKind } })
|
||||
},
|
||||
|
||||
output_toggle(outputId) {
|
||||
return axios.put(`./api/outputs/${outputId}/toggle`)
|
||||
},
|
||||
|
||||
output_update(outputId, output) {
|
||||
return axios.put(`./api/outputs/${outputId}`, output)
|
||||
},
|
||||
|
||||
outputs() {
|
||||
return axios.get('./api/outputs')
|
||||
},
|
||||
|
||||
pairing() {
|
||||
return axios.get('./api/pairing')
|
||||
},
|
||||
|
||||
pairing_kickoff(request) {
|
||||
return axios.post('./api/pairing', request)
|
||||
},
|
||||
|
||||
player_consume(state) {
|
||||
return axios.put(`./api/player/consume?state=${state}`)
|
||||
},
|
||||
|
||||
player_next() {
|
||||
return axios.put('./api/player/next')
|
||||
},
|
||||
|
||||
player_output_volume(outputId, outputVolume) {
|
||||
return axios.put(
|
||||
`./api/player/volume?volume=${outputVolume}&output_id=${outputId}`
|
||||
)
|
||||
},
|
||||
|
||||
player_pause() {
|
||||
return axios.put('./api/player/pause')
|
||||
},
|
||||
|
||||
player_play(options = {}) {
|
||||
return axios.put('./api/player/play', null, { params: options })
|
||||
},
|
||||
|
||||
player_play_expression(expression, shuffle, position) {
|
||||
const params = {
|
||||
clear: 'true',
|
||||
expression,
|
||||
playback: 'start',
|
||||
playback_from_position: position,
|
||||
shuffle
|
||||
}
|
||||
return axios.post('./api/queue/items/add', null, { params })
|
||||
},
|
||||
|
||||
player_play_uri(uris, shuffle, position) {
|
||||
const params = {
|
||||
clear: 'true',
|
||||
playback: 'start',
|
||||
playback_from_position: position,
|
||||
shuffle,
|
||||
uris
|
||||
}
|
||||
return axios.post('./api/queue/items/add', null, { params })
|
||||
},
|
||||
|
||||
player_previous() {
|
||||
return axios.put('./api/player/previous')
|
||||
},
|
||||
|
||||
player_repeat(mode) {
|
||||
return axios.put(`./api/player/repeat?state=${mode}`)
|
||||
},
|
||||
|
||||
player_seek(seekMs) {
|
||||
return axios.put(`./api/player/seek?seek_ms=${seekMs}`)
|
||||
},
|
||||
|
||||
player_seek_to_pos(position) {
|
||||
return axios.put(`./api/player/seek?position_ms=${position}`)
|
||||
},
|
||||
|
||||
player_shuffle(state) {
|
||||
return axios.put(`./api/player/shuffle?state=${state}`)
|
||||
},
|
||||
|
||||
player_status() {
|
||||
return axios.get('./api/player')
|
||||
},
|
||||
|
||||
player_stop() {
|
||||
return axios.put('./api/player/stop')
|
||||
},
|
||||
|
||||
player_volume(volume) {
|
||||
return axios.put(`./api/player/volume?volume=${volume}`)
|
||||
},
|
||||
|
||||
queue() {
|
||||
return axios.get('./api/queue')
|
||||
},
|
||||
|
||||
async queue_add(uri) {
|
||||
const data = await axios.post(`./api/queue/items/add?uris=${uri}`)
|
||||
useNotificationsStore().add({
|
||||
text: t('server.appended-tracks', { count: data.count }),
|
||||
timeout: 2000,
|
||||
type: 'info'
|
||||
})
|
||||
return await Promise.resolve(data)
|
||||
},
|
||||
|
||||
async queue_add_next(uri) {
|
||||
let position = 0
|
||||
const { current } = useQueueStore()
|
||||
if (current?.id) {
|
||||
position = current.position + 1
|
||||
}
|
||||
const data = await axios.post(
|
||||
`./api/queue/items/add?uris=${uri}&position=${position}`
|
||||
)
|
||||
useNotificationsStore().add({
|
||||
text: t('server.appended-tracks', { count: data.count }),
|
||||
timeout: 2000,
|
||||
type: 'info'
|
||||
})
|
||||
return await Promise.resolve(data)
|
||||
},
|
||||
|
||||
queue_clear() {
|
||||
return axios.put('./api/queue/clear')
|
||||
},
|
||||
|
||||
async queue_expression_add(expression) {
|
||||
const data = await axios.post('./api/queue/items/add', null, {
|
||||
params: { expression }
|
||||
})
|
||||
useNotificationsStore().add({
|
||||
text: t('server.appended-tracks', { count: data.count }),
|
||||
timeout: 2000,
|
||||
type: 'info'
|
||||
})
|
||||
return await Promise.resolve(data)
|
||||
},
|
||||
|
||||
async queue_expression_add_next(expression) {
|
||||
const params = {}
|
||||
params.expression = expression
|
||||
params.position = 0
|
||||
const { current } = useQueueStore()
|
||||
if (current?.id) {
|
||||
params.position = current.position + 1
|
||||
}
|
||||
const data = await axios.post('./api/queue/items/add', null, { params })
|
||||
useNotificationsStore().add({
|
||||
text: t('server.appended-tracks', { count: data.count }),
|
||||
timeout: 2000,
|
||||
type: 'info'
|
||||
})
|
||||
return await Promise.resolve(data)
|
||||
},
|
||||
|
||||
queue_move(itemId, position) {
|
||||
return axios.put(`./api/queue/items/${itemId}?new_position=${position}`)
|
||||
},
|
||||
|
||||
queue_remove(itemId) {
|
||||
return axios.delete(`./api/queue/items/${itemId}`)
|
||||
},
|
||||
|
||||
async queue_save_playlist(name) {
|
||||
const response = await axios.post('./api/queue/save', null, {
|
||||
params: { name }
|
||||
})
|
||||
useNotificationsStore().add({
|
||||
text: t('server.queue-saved', { name }),
|
||||
timeout: 2000,
|
||||
type: 'info'
|
||||
})
|
||||
return await Promise.resolve(response)
|
||||
},
|
||||
|
||||
search(params) {
|
||||
return axios.get('./api/search', { params })
|
||||
},
|
||||
|
||||
settings() {
|
||||
return axios.get('./api/settings')
|
||||
},
|
||||
|
||||
settings_update(categoryName, option) {
|
||||
return axios.put(`./api/settings/${categoryName}/${option.name}`, option)
|
||||
},
|
||||
|
||||
spotify() {
|
||||
return axios.get('./api/spotify')
|
||||
},
|
||||
|
||||
spotify_logout() {
|
||||
return axios.get('./api/spotify-logout')
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user