mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2024-12-27 00:59:14 +01:00
Sorting, fix user object bug, add settings module
This commit is contained in:
parent
9a74825bad
commit
6e8fe32bf5
@ -3,6 +3,7 @@ import { wrapFunctional } from './utils'
|
||||
export { default as AudioPlayer } from '../..\\components\\AudioPlayer.vue'
|
||||
export { default as AppAppbar } from '../..\\components\\app\\Appbar.vue'
|
||||
export { default as AppBookShelf } from '../..\\components\\app\\BookShelf.vue'
|
||||
export { default as AppBookShelfToolbar } from '../..\\components\\app\\BookShelfToolbar.vue'
|
||||
export { default as AppStreamContainer } from '../..\\components\\app\\StreamContainer.vue'
|
||||
export { default as AppTracksTable } from '../..\\components\\app\\TracksTable.vue'
|
||||
export { default as CardsBookCard } from '../..\\components\\cards\\BookCard.vue'
|
||||
@ -27,6 +28,7 @@ export { default as ModalsEditTabsTracks } from '../..\\components\\modals\\edit
|
||||
export const LazyAudioPlayer = import('../..\\components\\AudioPlayer.vue' /* webpackChunkName: "components/audio-player" */).then(c => wrapFunctional(c.default || c))
|
||||
export const LazyAppAppbar = import('../..\\components\\app\\Appbar.vue' /* webpackChunkName: "components/app-appbar" */).then(c => wrapFunctional(c.default || c))
|
||||
export const LazyAppBookShelf = import('../..\\components\\app\\BookShelf.vue' /* webpackChunkName: "components/app-book-shelf" */).then(c => wrapFunctional(c.default || c))
|
||||
export const LazyAppBookShelfToolbar = import('../..\\components\\app\\BookShelfToolbar.vue' /* webpackChunkName: "components/app-book-shelf-toolbar" */).then(c => wrapFunctional(c.default || c))
|
||||
export const LazyAppStreamContainer = import('../..\\components\\app\\StreamContainer.vue' /* webpackChunkName: "components/app-stream-container" */).then(c => wrapFunctional(c.default || c))
|
||||
export const LazyAppTracksTable = import('../..\\components\\app\\TracksTable.vue' /* webpackChunkName: "components/app-tracks-table" */).then(c => wrapFunctional(c.default || c))
|
||||
export const LazyCardsBookCard = import('../..\\components\\cards\\BookCard.vue' /* webpackChunkName: "components/cards-book-card" */).then(c => wrapFunctional(c.default || c))
|
||||
|
@ -5,6 +5,7 @@ const components = {
|
||||
AudioPlayer: () => import('../..\\components\\AudioPlayer.vue' /* webpackChunkName: "components/audio-player" */).then(c => wrapFunctional(c.default || c)),
|
||||
AppAppbar: () => import('../..\\components\\app\\Appbar.vue' /* webpackChunkName: "components/app-appbar" */).then(c => wrapFunctional(c.default || c)),
|
||||
AppBookShelf: () => import('../..\\components\\app\\BookShelf.vue' /* webpackChunkName: "components/app-book-shelf" */).then(c => wrapFunctional(c.default || c)),
|
||||
AppBookShelfToolbar: () => import('../..\\components\\app\\BookShelfToolbar.vue' /* webpackChunkName: "components/app-book-shelf-toolbar" */).then(c => wrapFunctional(c.default || c)),
|
||||
AppStreamContainer: () => import('../..\\components\\app\\StreamContainer.vue' /* webpackChunkName: "components/app-stream-container" */).then(c => wrapFunctional(c.default || c)),
|
||||
AppTracksTable: () => import('../..\\components\\app\\TracksTable.vue' /* webpackChunkName: "components/app-tracks-table" */).then(c => wrapFunctional(c.default || c)),
|
||||
CardsBookCard: () => import('../..\\components\\cards\\BookCard.vue' /* webpackChunkName: "components/cards-book-card" */).then(c => wrapFunctional(c.default || c)),
|
||||
|
@ -9,6 +9,7 @@ You can directly use them in pages and other components without the need to impo
|
||||
- `<AudioPlayer>` | `<audio-player>` (components/AudioPlayer.vue)
|
||||
- `<AppAppbar>` | `<app-appbar>` (components/app/Appbar.vue)
|
||||
- `<AppBookShelf>` | `<app-book-shelf>` (components/app/BookShelf.vue)
|
||||
- `<AppBookShelfToolbar>` | `<app-book-shelf-toolbar>` (components/app/BookShelfToolbar.vue)
|
||||
- `<AppStreamContainer>` | `<app-stream-container>` (components/app/StreamContainer.vue)
|
||||
- `<AppTracksTable>` | `<app-tracks-table>` (components/app/TracksTable.vue)
|
||||
- `<CardsBookCard>` | `<cards-book-card>` (components/cards/BookCard.vue)
|
||||
|
@ -20,6 +20,7 @@ let store = {};
|
||||
store.modules = store.modules || {}
|
||||
|
||||
resolveStoreModules(require('..\\store\\audiobooks.js'), 'audiobooks.js')
|
||||
resolveStoreModules(require('..\\store\\settings.js'), 'settings.js')
|
||||
|
||||
// If the environment supports hot reloading...
|
||||
|
||||
@ -28,6 +29,7 @@ let store = {};
|
||||
module.hot.accept([
|
||||
'..\\store\\audiobooks.js',
|
||||
'..\\store\\index.js',
|
||||
'..\\store\\settings.js',
|
||||
], () => {
|
||||
// Update `root.modules` with the latest definitions.
|
||||
updateModules()
|
||||
|
@ -8,6 +8,9 @@
|
||||
"AppBookShelf": {
|
||||
"description": "Auto imported from components/app/BookShelf.vue"
|
||||
},
|
||||
"AppBookShelfToolbar": {
|
||||
"description": "Auto imported from components/app/BookShelfToolbar.vue"
|
||||
},
|
||||
"AppStreamContainer": {
|
||||
"description": "Auto imported from components/app/StreamContainer.vue"
|
||||
},
|
||||
|
@ -83,6 +83,7 @@ export default {
|
||||
|
||||
<style>
|
||||
#appbar {
|
||||
box-shadow: 0px 8px 8px #111111aa;
|
||||
/* box-shadow: 0px 8px 8px #111111aa; */
|
||||
box-shadow: 0px 5px 5px #11111155;
|
||||
}
|
||||
</style>
|
@ -35,21 +35,43 @@ export default {
|
||||
},
|
||||
audiobooks() {
|
||||
return this.$store.state.audiobooks.audiobooks
|
||||
},
|
||||
orderBy() {
|
||||
return this.$store.state.settings.orderBy
|
||||
},
|
||||
orderDesc() {
|
||||
return this.$store.state.settings.orderDesc
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
sortAudiobooks() {
|
||||
var audiobooks = this.audiobooks.map((ab) => ({ ...ab }))
|
||||
audiobooks.sort((a, b) => {
|
||||
var bookA = a.book || {}
|
||||
var bookB = b.book || {}
|
||||
if (this.orderDesc) {
|
||||
return bookB[this.orderBy] > bookA[this.orderBy] ? 1 : -1
|
||||
} else {
|
||||
// ASCENDING A -> Z
|
||||
return bookA[this.orderBy] > bookB[this.orderBy] ? 1 : -1
|
||||
}
|
||||
})
|
||||
return audiobooks
|
||||
},
|
||||
setGroupedBooks() {
|
||||
var groups = []
|
||||
var currentRow = 0
|
||||
var currentGroup = []
|
||||
for (let i = 0; i < this.audiobooks.length; i++) {
|
||||
var audiobooksSorted = this.sortAudiobooks()
|
||||
console.log('AB SORTED', audiobooksSorted)
|
||||
for (let i = 0; i < audiobooksSorted.length; i++) {
|
||||
var row = Math.floor(i / this.booksPerRow)
|
||||
if (row > currentRow) {
|
||||
groups.push([...currentGroup])
|
||||
currentRow = row
|
||||
currentGroup = []
|
||||
}
|
||||
currentGroup.push(this.audiobooks[i])
|
||||
currentGroup.push(audiobooksSorted[i])
|
||||
}
|
||||
if (currentGroup.length) {
|
||||
groups.push([...currentGroup])
|
||||
@ -98,6 +120,9 @@ export default {
|
||||
</script>
|
||||
|
||||
<style>
|
||||
#bookshelf {
|
||||
height: calc(100% - 40px);
|
||||
}
|
||||
.bookshelfRow {
|
||||
background-image: url(/wood_panels.jpg);
|
||||
}
|
||||
|
33
client/components/app/BookShelfToolbar.vue
Normal file
33
client/components/app/BookShelfToolbar.vue
Normal file
@ -0,0 +1,33 @@
|
||||
<template>
|
||||
<div class="w-full h-10 relative">
|
||||
<div id="toolbar" class="absolute top-0 left-0 w-full h-full z-10 flex items-center px-8">
|
||||
<p>Order By: {{ orderBy }}</p>
|
||||
<p class="px-4">Desc: {{ orderDesc ? 'Desc' : 'Asc' }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {}
|
||||
},
|
||||
computed: {
|
||||
orderBy() {
|
||||
return this.$store.state.settings.orderBy
|
||||
},
|
||||
orderDesc() {
|
||||
return this.$store.state.settings.orderDesc
|
||||
}
|
||||
},
|
||||
methods: {},
|
||||
mounted() {}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<style>
|
||||
#toolbar {
|
||||
box-shadow: 0px 8px 8px #111111aa;
|
||||
}
|
||||
</style>
|
@ -11,6 +11,9 @@
|
||||
<div v-show="processing" class="flex h-full items-center justify-center">
|
||||
<p>Loading...</p>
|
||||
</div>
|
||||
<div v-show="!processing && !searchResults.length" class="flex h-full items-center justify-center">
|
||||
<p>No Results</p>
|
||||
</div>
|
||||
<div v-show="!processing" class="w-full max-h-full overflow-y-auto overflow-x-hidden">
|
||||
<template v-for="(res, index) in searchResults">
|
||||
<div :key="index" class="w-full border-b border-gray-700 pb-2 hover:bg-gray-300 hover:bg-opacity-10 cursor-pointer" @click="selectMatch(res)">
|
||||
@ -42,6 +45,7 @@
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
processing: Boolean,
|
||||
audiobook: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
@ -63,7 +67,16 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {},
|
||||
computed: {
|
||||
isProcessing: {
|
||||
get() {
|
||||
return this.processing
|
||||
},
|
||||
set(val) {
|
||||
this.$emit('update:processing', val)
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
submitSearch() {
|
||||
this.runSearch()
|
||||
@ -75,7 +88,13 @@ export default {
|
||||
this.searchResults = []
|
||||
this.processing = true
|
||||
this.lastSearch = this.search
|
||||
var results = await this.$axios.$get(`/api/find/search?title=${this.search}`)
|
||||
var results = await this.$axios.$get(`/api/find/search?title=${this.search}`).catch((error) => {
|
||||
console.error('Failed', error)
|
||||
return []
|
||||
})
|
||||
results = results.filter((res) => {
|
||||
return !!res.title
|
||||
})
|
||||
console.log('Got results', results)
|
||||
this.searchResults = results
|
||||
this.processing = false
|
||||
@ -91,10 +110,31 @@ export default {
|
||||
this.search = this.audiobook.book.title
|
||||
this.runSearch()
|
||||
},
|
||||
selectMatch(match) {}
|
||||
},
|
||||
mounted() {
|
||||
console.log('Match mounted')
|
||||
async selectMatch(match) {
|
||||
this.isProcessing = true
|
||||
const updatePayload = {
|
||||
book: {}
|
||||
}
|
||||
if (match.cover) {
|
||||
updatePayload.book.cover = match.cover
|
||||
}
|
||||
if (match.title) {
|
||||
updatePayload.book.title = match.title
|
||||
}
|
||||
if (match.description) {
|
||||
updatePayload.book.description = match.description
|
||||
}
|
||||
var updatedAudiobook = await this.$axios.$patch(`/api/audiobook/${this.audiobook.id}`, updatePayload).catch((error) => {
|
||||
console.error('Failed to update', error)
|
||||
return false
|
||||
})
|
||||
this.isProcessing = false
|
||||
if (updatedAudiobook) {
|
||||
console.log('Update Successful', updatedAudiobook)
|
||||
this.$toast.success('Update Successful')
|
||||
this.$emit('close')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
@ -50,6 +50,9 @@ export default {
|
||||
mouseleave() {
|
||||
if (this.isShowing) this.hideTooltip()
|
||||
}
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.hideTooltip()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "audiobookshelf-client",
|
||||
"version": "0.9.1",
|
||||
"version": "0.9.3",
|
||||
"description": "Audiobook manager and player",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
|
@ -13,7 +13,9 @@
|
||||
<ui-btn color="success" @click="scan">Scan</ui-btn>
|
||||
</div>
|
||||
<div class="h-0.5 bg-primary bg-opacity-50 w-full" />
|
||||
<p class="font-mono">v{{ $config.version }}</p>
|
||||
<div class="flex items-center py-4">
|
||||
<p class="font-mono">v{{ $config.version }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@ -23,7 +25,11 @@ export default {
|
||||
data() {
|
||||
return {}
|
||||
},
|
||||
computed: {},
|
||||
computed: {
|
||||
streamAudiobook() {
|
||||
return this.$store.state.streamAudiobook
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
scan() {
|
||||
this.$root.socket.emit('scan')
|
||||
|
@ -1,5 +1,6 @@
|
||||
<template>
|
||||
<div class="page" :class="streamAudiobook ? 'streaming' : ''">
|
||||
<app-book-shelf-toolbar />
|
||||
<app-book-shelf />
|
||||
</div>
|
||||
</template>
|
||||
|
20
client/store/settings.js
Normal file
20
client/store/settings.js
Normal file
@ -0,0 +1,20 @@
|
||||
|
||||
export const state = () => ({
|
||||
orderBy: 'title',
|
||||
orderDesc: false
|
||||
})
|
||||
|
||||
export const getters = {
|
||||
|
||||
}
|
||||
|
||||
export const actions = {
|
||||
|
||||
}
|
||||
|
||||
export const mutations = {
|
||||
setSettings(state, settings) {
|
||||
state.orderBy = settings.orderBy
|
||||
state.orderDesc = settings.orderDesc
|
||||
}
|
||||
}
|
@ -1,13 +1,18 @@
|
||||
const defaultTheme = require('tailwindcss/defaultTheme')
|
||||
|
||||
module.exports = {
|
||||
purge: {},
|
||||
purge: {
|
||||
options: {
|
||||
safelist: [
|
||||
'bg-success'
|
||||
]
|
||||
}
|
||||
},
|
||||
darkMode: false,
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
bg: '#373838',
|
||||
yellowgreen: 'yellowgreen',
|
||||
primary: '#262626',
|
||||
accent: '#1ad691',
|
||||
error: '#FF5252',
|
||||
|
@ -8,7 +8,7 @@
|
||||
<Shell>sh</Shell>
|
||||
<Privileged>false</Privileged>
|
||||
<Support>https://hub.docker.com/r/advplyr/audiobookshelf/</Support>
|
||||
<Project/>
|
||||
<Project>https://github.com/advplyr/audiobookshelf</Project>
|
||||
<Overview>Audiobook manager and player</Overview>
|
||||
<Category>MediaApp:Books MediaServer:Books Status:Beta<</Category>
|
||||
<WebUI>http://[IP]:[PORT:80]</WebUI>
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "audiobookshelf",
|
||||
"version": "0.9.1",
|
||||
"version": "0.9.3",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
|
@ -115,8 +115,12 @@ class StreamManager {
|
||||
Logger.error('No User for client', client)
|
||||
return
|
||||
}
|
||||
if (!client.user.updateAudiobookProgress) {
|
||||
Logger.error('Invalid User for client', client)
|
||||
return
|
||||
}
|
||||
client.user.updateAudiobookProgress(client.stream)
|
||||
this.db.updateEntity('user', client.user.toJSON())
|
||||
this.db.updateEntity('user', client.user)
|
||||
}
|
||||
}
|
||||
module.exports = StreamManager
|
Loading…
Reference in New Issue
Block a user