mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2024-12-26 16:48:53 +01:00
Pkg scripts win/linux
This commit is contained in:
parent
6cb418a871
commit
94741598af
@ -102,3 +102,7 @@
|
|||||||
.box-shadow-book {
|
.box-shadow-book {
|
||||||
box-shadow: 4px 1px 8px #11111166, -4px 1px 8px #11111166, 1px -4px 8px #11111166;
|
box-shadow: 4px 1px 8px #11111166, -4px 1px 8px #11111166, 1px -4px 8px #11111166;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.box-shadow-side {
|
||||||
|
box-shadow: 4px 0px 4px #11111166;
|
||||||
|
}
|
||||||
|
@ -7,15 +7,16 @@
|
|||||||
<span class="material-icons text-4xl text-white">arrow_back</span>
|
<span class="material-icons text-4xl text-white">arrow_back</span>
|
||||||
</a>
|
</a>
|
||||||
<h1 class="text-2xl font-book mr-6">AudioBookshelf</h1>
|
<h1 class="text-2xl font-book mr-6">AudioBookshelf</h1>
|
||||||
|
<!-- <div class="-mb-2">
|
||||||
|
<h1 class="text-lg font-book leading-3 mr-6 px-1">AudioBookshelf</h1>
|
||||||
|
<div class="bg-black bg-opacity-20 rounded-sm py-1.5 px-2 mt-1.5 flex items-center justify-between border border-bg">
|
||||||
|
<p class="text-sm text-gray-400 leading-3">My Library</p>
|
||||||
|
<span class="material-icons text-sm leading-3 text-gray-400">expand_more</span>
|
||||||
|
</div>
|
||||||
|
</div> -->
|
||||||
<controls-global-search />
|
<controls-global-search />
|
||||||
<div class="flex-grow" />
|
<div class="flex-grow" />
|
||||||
|
|
||||||
<!-- <a v-if="isUpdateAvailable" :href="githubTagUrl" target="_blank" class="flex items-center rounded-full bg-warning p-2 text-sm">
|
|
||||||
<span class="material-icons">notification_important</span>
|
|
||||||
<span class="pl-2">Update is available! Check release notes for v{{ latestVersion }}</span>
|
|
||||||
</a> -->
|
|
||||||
|
|
||||||
<nuxt-link v-if="userCanUpload" to="/upload" class="outline-none hover:text-gray-200 cursor-pointer w-8 h-8 flex items-center justify-center">
|
<nuxt-link v-if="userCanUpload" to="/upload" class="outline-none hover:text-gray-200 cursor-pointer w-8 h-8 flex items-center justify-center">
|
||||||
<span class="material-icons">upload</span>
|
<span class="material-icons">upload</span>
|
||||||
</nuxt-link>
|
</nuxt-link>
|
||||||
@ -45,10 +46,8 @@
|
|||||||
</ui-tooltip>
|
</ui-tooltip>
|
||||||
<template v-if="userCanUpdate">
|
<template v-if="userCanUpdate">
|
||||||
<ui-icon-btn v-show="!processingBatchDelete" icon="edit" bg-color="warning" class="mx-1.5" @click="batchEditClick" />
|
<ui-icon-btn v-show="!processingBatchDelete" icon="edit" bg-color="warning" class="mx-1.5" @click="batchEditClick" />
|
||||||
<!-- <ui-btn v-show="!processingBatchDelete" color="warning" small class="mx-2 w-10 h-10" :padding-y="0" :padding-x="0" @click="batchEditClick"><span class="material-icons text-gray-200 text-base">edit</span></ui-btn> -->
|
|
||||||
</template>
|
</template>
|
||||||
<ui-icon-btn v-show="userCanDelete" :disabled="processingBatchDelete" icon="delete" bg-color="error" class="mx-1.5" @click="batchDeleteClick" />
|
<ui-icon-btn v-show="userCanDelete" :disabled="processingBatchDelete" icon="delete" bg-color="error" class="mx-1.5" @click="batchDeleteClick" />
|
||||||
<!-- <ui-btn v-if="userCanDelete" color="error" small class="mx-2" :loading="processingBatchDelete" @click="batchDeleteClick"><span class="material-icons text-gray-200 pt-1">delete</span></ui-btn> -->
|
|
||||||
<span class="material-icons text-4xl px-4 hover:text-gray-100 cursor-pointer" :class="processingBatchDelete ? 'text-gray-400' : ''" @click="cancelSelectionMode">close</span>
|
<span class="material-icons text-4xl px-4 hover:text-gray-100 cursor-pointer" :class="processingBatchDelete ? 'text-gray-400' : ''" @click="cancelSelectionMode">close</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -17,17 +17,18 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="w-full flex flex-col items-center">
|
<div v-else class="w-full flex flex-col items-center">
|
||||||
<template v-for="(shelf, index) in groupedBooks">
|
<template v-for="(shelf, index) in entities">
|
||||||
<div :key="index" class="w-full bookshelfRow relative">
|
<div :key="index" class="w-full bookshelfRow relative">
|
||||||
<div class="flex justify-center items-center">
|
<div class="flex justify-center items-center">
|
||||||
<template v-for="audiobook in shelf">
|
<template v-for="entity in shelf">
|
||||||
<cards-book-card :ref="`audiobookCard-${audiobook.id}`" :key="audiobook.id" :width="bookCoverWidth" :user-progress="userAudiobooks[audiobook.id]" :audiobook="audiobook" />
|
<cards-group-card v-if="page !== ''" :key="entity.id" :width="bookCoverWidth" :group="entity" />
|
||||||
|
<cards-book-card v-else :key="entity.id" :width="bookCoverWidth" :user-progress="userAudiobooks[entity.id]" :audiobook="entity" />
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
<div class="bookshelfDivider h-4 w-full absolute bottom-0 left-0 right-0 z-10" />
|
<div class="bookshelfDivider h-4 w-full absolute bottom-0 left-0 right-0 z-10" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<div v-show="!groupedBooks.length" class="w-full py-16 text-center text-xl">
|
<div v-show="!entities.length" class="w-full py-16 text-center text-xl">
|
||||||
<div class="py-4">No Audiobooks</div>
|
<div class="py-4">No Audiobooks</div>
|
||||||
<ui-btn v-if="filterBy !== 'all' || keywordFilter" @click="clearFilter">Clear Filter</ui-btn>
|
<ui-btn v-if="filterBy !== 'all' || keywordFilter" @click="clearFilter">Clear Filter</ui-btn>
|
||||||
</div>
|
</div>
|
||||||
@ -37,11 +38,14 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
|
props: {
|
||||||
|
page: String
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
width: 0,
|
width: 0,
|
||||||
booksPerRow: 0,
|
booksPerRow: 0,
|
||||||
groupedBooks: [],
|
entities: [],
|
||||||
currFilterOrderKey: null,
|
currFilterOrderKey: null,
|
||||||
availableSizes: [60, 80, 100, 120, 140, 160, 180, 200, 220],
|
availableSizes: [60, 80, 100, 120, 140, 160, 180, 200, 220],
|
||||||
selectedSizeIndex: 3,
|
selectedSizeIndex: 3,
|
||||||
@ -95,13 +99,13 @@ export default {
|
|||||||
filterBy: 'all'
|
filterBy: 'all'
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
this.setGroupedBooks()
|
this.setBookshelfEntities()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
checkKeywordFilter() {
|
checkKeywordFilter() {
|
||||||
clearTimeout(this.keywordFilterTimeout)
|
clearTimeout(this.keywordFilterTimeout)
|
||||||
this.keywordFilterTimeout = setTimeout(() => {
|
this.keywordFilterTimeout = setTimeout(() => {
|
||||||
this.setGroupedBooks()
|
this.setBookshelfEntities()
|
||||||
}, 500)
|
}, 500)
|
||||||
},
|
},
|
||||||
increaseSize() {
|
increaseSize() {
|
||||||
@ -114,27 +118,34 @@ export default {
|
|||||||
this.resize()
|
this.resize()
|
||||||
this.$store.dispatch('user/updateUserSettings', { bookshelfCoverSize: this.bookCoverWidth })
|
this.$store.dispatch('user/updateUserSettings', { bookshelfCoverSize: this.bookCoverWidth })
|
||||||
},
|
},
|
||||||
setGroupedBooks() {
|
setBookshelfEntities() {
|
||||||
|
if (this.page === '') {
|
||||||
|
var audiobooksSorted = this.$store.getters['audiobooks/getFilteredAndSorted']()
|
||||||
|
this.currFilterOrderKey = this.filterOrderKey
|
||||||
|
this.setGroupedBooks(audiobooksSorted)
|
||||||
|
} else {
|
||||||
|
var entities = this.$store.getters['audiobooks/getSeriesGroups']()
|
||||||
|
this.setGroupedBooks(entities)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setGroupedBooks(entities) {
|
||||||
var groups = []
|
var groups = []
|
||||||
var currentRow = 0
|
var currentRow = 0
|
||||||
var currentGroup = []
|
var currentGroup = []
|
||||||
|
|
||||||
var audiobooksSorted = this.$store.getters['audiobooks/getFilteredAndSorted']()
|
for (let i = 0; i < entities.length; i++) {
|
||||||
this.currFilterOrderKey = this.filterOrderKey
|
|
||||||
|
|
||||||
for (let i = 0; i < audiobooksSorted.length; i++) {
|
|
||||||
var row = Math.floor(i / this.booksPerRow)
|
var row = Math.floor(i / this.booksPerRow)
|
||||||
if (row > currentRow) {
|
if (row > currentRow) {
|
||||||
groups.push([...currentGroup])
|
groups.push([...currentGroup])
|
||||||
currentRow = row
|
currentRow = row
|
||||||
currentGroup = []
|
currentGroup = []
|
||||||
}
|
}
|
||||||
currentGroup.push(audiobooksSorted[i])
|
currentGroup.push(entities[i])
|
||||||
}
|
}
|
||||||
if (currentGroup.length) {
|
if (currentGroup.length) {
|
||||||
groups.push([...currentGroup])
|
groups.push([...currentGroup])
|
||||||
}
|
}
|
||||||
this.groupedBooks = groups
|
this.entities = groups
|
||||||
},
|
},
|
||||||
calculateBookshelf() {
|
calculateBookshelf() {
|
||||||
this.width = this.$refs.wrapper.clientWidth
|
this.width = this.$refs.wrapper.clientWidth
|
||||||
@ -142,12 +153,6 @@ export default {
|
|||||||
var booksPerRow = Math.floor(this.width / this.bookWidth)
|
var booksPerRow = Math.floor(this.width / this.bookWidth)
|
||||||
this.booksPerRow = booksPerRow
|
this.booksPerRow = booksPerRow
|
||||||
},
|
},
|
||||||
getAudiobookCard(id) {
|
|
||||||
if (this.$refs[`audiobookCard-${id}`] && this.$refs[`audiobookCard-${id}`].length) {
|
|
||||||
return this.$refs[`audiobookCard-${id}`][0]
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
},
|
|
||||||
init() {
|
init() {
|
||||||
var bookshelfCoverSize = this.$store.getters['user/getUserSetting']('bookshelfCoverSize')
|
var bookshelfCoverSize = this.$store.getters['user/getUserSetting']('bookshelfCoverSize')
|
||||||
var sizeIndex = this.availableSizes.findIndex((s) => s === bookshelfCoverSize)
|
var sizeIndex = this.availableSizes.findIndex((s) => s === bookshelfCoverSize)
|
||||||
@ -157,16 +162,16 @@ export default {
|
|||||||
resize() {
|
resize() {
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.calculateBookshelf()
|
this.calculateBookshelf()
|
||||||
this.setGroupedBooks()
|
this.setBookshelfEntities()
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
audiobooksUpdated() {
|
audiobooksUpdated() {
|
||||||
console.log('[AudioBookshelf] Audiobooks Updated')
|
console.log('[AudioBookshelf] Audiobooks Updated')
|
||||||
this.setGroupedBooks()
|
this.setBookshelfEntities()
|
||||||
},
|
},
|
||||||
settingsUpdated(settings) {
|
settingsUpdated(settings) {
|
||||||
if (this.currFilterOrderKey !== this.filterOrderKey) {
|
if (this.currFilterOrderKey !== this.filterOrderKey) {
|
||||||
this.setGroupedBooks()
|
this.setBookshelfEntities()
|
||||||
}
|
}
|
||||||
if (settings.bookshelfCoverSize !== this.bookCoverWidth && settings.bookshelfCoverSize !== undefined) {
|
if (settings.bookshelfCoverSize !== this.bookCoverWidth && settings.bookshelfCoverSize !== undefined) {
|
||||||
var index = this.availableSizes.indexOf(settings.bookshelfCoverSize)
|
var index = this.availableSizes.indexOf(settings.bookshelfCoverSize)
|
||||||
|
71
client/components/app/SideRail.vue
Normal file
71
client/components/app/SideRail.vue
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
<template>
|
||||||
|
<div class="w-20 border-r border-primary bg-bg h-full relative box-shadow-side z-20">
|
||||||
|
<nuxt-link to="/library" class="w-full h-20 flex flex-col items-center justify-center text-white border-b border-primary border-opacity-70 hover:bg-primary cursor-pointer relative" :class="paramId === '' ? 'bg-primary bg-opacity-80' : 'bg-bg bg-opacity-60'">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253" />
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
<p class="font-book pt-1.5" style="font-size: 0.8rem">Library</p>
|
||||||
|
|
||||||
|
<div v-show="paramId === ''" class="h-0.5 w-full bg-yellow-400 absolute bottom-0 left-0" />
|
||||||
|
</nuxt-link>
|
||||||
|
|
||||||
|
<nuxt-link to="/library/series" class="w-full h-20 flex flex-col items-center justify-center text-white text-opacity-80 border-b border-primary border-opacity-70 hover:bg-primary cursor-pointer relative" :class="paramId === 'series' ? 'bg-primary bg-opacity-80' : 'bg-bg bg-opacity-60'">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 17V7m0 10a2 2 0 01-2 2H5a2 2 0 01-2-2V7a2 2 0 012-2h2a2 2 0 012 2m0 10a2 2 0 002 2h2a2 2 0 002-2M9 7a2 2 0 012-2h2a2 2 0 012 2m0 10V7m0 10a2 2 0 002 2h2a2 2 0 002-2V7a2 2 0 00-2-2h-2a2 2 0 00-2 2" />
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
<p class="font-book pt-1.5" style="font-size: 0.8rem">Series</p>
|
||||||
|
|
||||||
|
<div v-show="paramId === 'series'" class="h-0.5 w-full bg-yellow-400 absolute bottom-0 left-0" />
|
||||||
|
</nuxt-link>
|
||||||
|
|
||||||
|
<nuxt-link to="/library/collections" class="w-full h-20 flex flex-col items-center justify-center text-white text-opacity-80 border-b border-primary border-opacity-70 hover:bg-primary cursor-pointer relative" :class="paramId === 'collections' ? 'bg-primary bg-opacity-80' : 'bg-bg bg-opacity-60'">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10" />
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
<p class="font-book pt-1.5" style="font-size: 0.8rem">Collections</p>
|
||||||
|
|
||||||
|
<div v-show="paramId === 'collections'" class="h-0.5 w-full bg-yellow-400 absolute bottom-0 left-0" />
|
||||||
|
</nuxt-link>
|
||||||
|
|
||||||
|
<nuxt-link to="/library/tags" class="w-full h-20 flex flex-col items-center justify-center text-white text-opacity-80 border-b border-primary border-opacity-70 hover:bg-primary cursor-pointer relative" :class="paramId === 'tags' ? 'bg-primary bg-opacity-80' : 'bg-bg bg-opacity-60'">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 7h.01M7 3h5c.512 0 1.024.195 1.414.586l7 7a2 2 0 010 2.828l-7 7a2 2 0 01-2.828 0l-7-7A1.994 1.994 0 013 12V7a4 4 0 014-4z" />
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
<p class="font-book pt-1.5" style="font-size: 0.8rem">Tags</p>
|
||||||
|
|
||||||
|
<div v-show="paramId === 'tags'" class="h-0.5 w-full bg-yellow-400 absolute bottom-0 left-0" />
|
||||||
|
</nuxt-link>
|
||||||
|
|
||||||
|
<nuxt-link to="/library/authors" class="w-full h-20 flex flex-col items-center justify-center text-white text-opacity-80 border-b border-primary border-opacity-70 hover:bg-primary cursor-pointer relative" :class="paramId === 'authors' ? 'bg-primary bg-opacity-80' : 'bg-bg bg-opacity-60'">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197M13 7a4 4 0 11-8 0 4 4 0 018 0z" />
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
<p class="font-book pt-1.5" style="font-size: 0.8rem">Authors</p>
|
||||||
|
|
||||||
|
<div v-show="paramId === 'authors'" class="h-0.5 w-full bg-yellow-400 absolute bottom-0 left-0" />
|
||||||
|
</nuxt-link>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
paramId() {
|
||||||
|
return this.$route.params ? this.$route.params.id || '' : ''
|
||||||
|
},
|
||||||
|
selectedClassName() {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {},
|
||||||
|
mounted() {}
|
||||||
|
}
|
||||||
|
</script>
|
56
client/components/cards/GroupCard.vue
Normal file
56
client/components/cards/GroupCard.vue
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
<template>
|
||||||
|
<div class="relative">
|
||||||
|
<div class="rounded-sm h-full overflow-hidden relative" :style="{ padding: `16px ${paddingX}px` }" @mouseover="isHovering = true" @mouseleave="isHovering = false" @click="clickCard">
|
||||||
|
<nuxt-link :to="`/library`" class="cursor-pointer">
|
||||||
|
<div class="w-full relative box-shadow-book bg-primary" :style="{ height: height + 'px', width: height + 'px' }"></div>
|
||||||
|
</nuxt-link>
|
||||||
|
</div>
|
||||||
|
<!-- <div :style="{ width: height + 'px', height: height + 'px' }" class="box-shadow-book bg-primary">
|
||||||
|
<p class="text-white">{{ groupName }}</p>
|
||||||
|
</div> -->
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
group: {
|
||||||
|
type: Object,
|
||||||
|
default: () => null
|
||||||
|
},
|
||||||
|
width: {
|
||||||
|
type: Number,
|
||||||
|
default: 120
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
isHovering: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
_group() {
|
||||||
|
return this.group || {}
|
||||||
|
},
|
||||||
|
height() {
|
||||||
|
return this.width * 1.6
|
||||||
|
},
|
||||||
|
sizeMultiplier() {
|
||||||
|
return this.width / 120
|
||||||
|
},
|
||||||
|
paddingX() {
|
||||||
|
return 16 * this.sizeMultiplier
|
||||||
|
},
|
||||||
|
books() {
|
||||||
|
return this._group.books || []
|
||||||
|
},
|
||||||
|
groupName() {
|
||||||
|
return this._group.name || 'No Name'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
clickCard() {}
|
||||||
|
},
|
||||||
|
mounted() {}
|
||||||
|
}
|
||||||
|
</script>
|
@ -1,7 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="text-white max-h-screen h-screen overflow-hidden bg-bg">
|
<div class="text-white max-h-screen h-screen overflow-hidden bg-bg">
|
||||||
<app-appbar />
|
<app-appbar />
|
||||||
|
|
||||||
<Nuxt />
|
<Nuxt />
|
||||||
|
|
||||||
<app-stream-container ref="streamContainer" />
|
<app-stream-container ref="streamContainer" />
|
||||||
<modals-edit-modal />
|
<modals-edit-modal />
|
||||||
<widgets-scan-alert />
|
<widgets-scan-alert />
|
||||||
|
@ -1,7 +1,12 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="page" :class="streamAudiobook ? 'streaming' : ''">
|
<div class="page" :class="streamAudiobook ? 'streaming' : ''">
|
||||||
<app-book-shelf-toolbar />
|
<app-book-shelf-toolbar />
|
||||||
|
<!-- <div class="flex h-full">
|
||||||
|
<app-side-rail />
|
||||||
|
<div class="flex-grow"> -->
|
||||||
<app-book-shelf />
|
<app-book-shelf />
|
||||||
|
<!-- </div> -->
|
||||||
|
<!-- </div> -->
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
31
client/pages/library/_id.vue
Normal file
31
client/pages/library/_id.vue
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<template>
|
||||||
|
<div class="page" :class="streamAudiobook ? 'streaming' : ''">
|
||||||
|
<div class="flex h-full">
|
||||||
|
<app-side-rail />
|
||||||
|
<div class="flex-grow">
|
||||||
|
<app-book-shelf-toolbar />
|
||||||
|
<app-book-shelf :page="id || ''" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
asyncData({ params }) {
|
||||||
|
return {
|
||||||
|
id: params.id
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
streamAudiobook() {
|
||||||
|
return this.$store.state.streamAudiobook
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {},
|
||||||
|
mounted() {}
|
||||||
|
}
|
||||||
|
</script>
|
@ -63,6 +63,23 @@ export const getters = {
|
|||||||
return value
|
return value
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
getSeriesGroups: (state, getters, rootState) => () => {
|
||||||
|
var series = {}
|
||||||
|
state.audiobooks.forEach((audiobook) => {
|
||||||
|
if (audiobook.book && audiobook.book.series) {
|
||||||
|
if (series[audiobook.book.series]) {
|
||||||
|
series[audiobook.book.series].books.push(audiobook)
|
||||||
|
} else {
|
||||||
|
series[audiobook.book.series] = {
|
||||||
|
type: 'series',
|
||||||
|
name: audiobook.book.series,
|
||||||
|
books: [audiobook]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return Object.values(series)
|
||||||
|
},
|
||||||
getUniqueAuthors: (state) => {
|
getUniqueAuthors: (state) => {
|
||||||
var _authors = state.audiobooks.filter(ab => !!(ab.book && ab.book.author)).map(ab => ab.book.author)
|
var _authors = state.audiobooks.filter(ab => !!(ab.book && ab.book.author)).map(ab => ab.book.author)
|
||||||
return [...new Set(_authors)].sort((a, b) => a.toLowerCase() < b.toLowerCase() ? -1 : 1)
|
return [...new Set(_authors)].sort((a, b) => a.toLowerCase() < b.toLowerCase() ? -1 : 1)
|
||||||
|
12
package.json
12
package.json
@ -7,7 +7,17 @@
|
|||||||
"dev": "node index.js",
|
"dev": "node index.js",
|
||||||
"start": "node index.js",
|
"start": "node index.js",
|
||||||
"client": "cd client && npm install && npm run generate",
|
"client": "cd client && npm install && npm run generate",
|
||||||
"prod": "npm run client && npm install && node prod.js"
|
"prod": "npm run client && npm install && node prod.js",
|
||||||
|
"build-win": "cd client && npm run generate && cd .. && pkg -t node12-win-x64 -o ./dist/app .",
|
||||||
|
"build-linux": "pkg -t node12-linux-arm64 -o ./dist/app ."
|
||||||
|
},
|
||||||
|
"bin": "prod.js",
|
||||||
|
"pkg": {
|
||||||
|
"assets": "client/dist/**/*",
|
||||||
|
"scripts": [
|
||||||
|
"prod.js",
|
||||||
|
"server/**/*.js"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"author": "advplyr",
|
"author": "advplyr",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
|
3
prod.js
3
prod.js
@ -13,6 +13,7 @@ process.env.TOKEN_SECRET = '09f26e402586e2faa8da4c98a35f1b20d6b033c6097befa8be34
|
|||||||
process.env.NODE_ENV = 'production'
|
process.env.NODE_ENV = 'production'
|
||||||
|
|
||||||
const server = require('./server/Server')
|
const server = require('./server/Server')
|
||||||
|
|
||||||
global.appRoot = __dirname
|
global.appRoot = __dirname
|
||||||
|
|
||||||
var inputConfig = options.config ? Path.resolve(options.config) : null
|
var inputConfig = options.config ? Path.resolve(options.config) : null
|
||||||
@ -24,7 +25,7 @@ const CONFIG_PATH = inputConfig || process.env.CONFIG_PATH || Path.resolve('conf
|
|||||||
const AUDIOBOOK_PATH = inputAudiobook || process.env.AUDIOBOOK_PATH || Path.resolve('audiobooks')
|
const AUDIOBOOK_PATH = inputAudiobook || process.env.AUDIOBOOK_PATH || Path.resolve('audiobooks')
|
||||||
const METADATA_PATH = inputMetadata || process.env.METADATA_PATH || Path.resolve('metadata')
|
const METADATA_PATH = inputMetadata || process.env.METADATA_PATH || Path.resolve('metadata')
|
||||||
|
|
||||||
console.log('Config', CONFIG_PATH, METADATA_PATH, AUDIOBOOK_PATH)
|
console.log(process.env.NODE_ENV, 'Config', CONFIG_PATH, METADATA_PATH, AUDIOBOOK_PATH)
|
||||||
|
|
||||||
const Server = new server(PORT, CONFIG_PATH, METADATA_PATH, AUDIOBOOK_PATH)
|
const Server = new server(PORT, CONFIG_PATH, METADATA_PATH, AUDIOBOOK_PATH)
|
||||||
Server.start()
|
Server.start()
|
||||||
|
@ -113,6 +113,7 @@ class Server {
|
|||||||
await this.streamManager.ensureStreamsDir()
|
await this.streamManager.ensureStreamsDir()
|
||||||
await this.streamManager.removeOrphanStreams()
|
await this.streamManager.removeOrphanStreams()
|
||||||
await this.downloadManager.removeOrphanDownloads()
|
await this.downloadManager.removeOrphanDownloads()
|
||||||
|
|
||||||
await this.db.init()
|
await this.db.init()
|
||||||
this.auth.init()
|
this.auth.init()
|
||||||
|
|
||||||
@ -171,7 +172,6 @@ class Server {
|
|||||||
|
|
||||||
async start() {
|
async start() {
|
||||||
Logger.info('=== Starting Server ===')
|
Logger.info('=== Starting Server ===')
|
||||||
|
|
||||||
await this.init()
|
await this.init()
|
||||||
|
|
||||||
const app = express()
|
const app = express()
|
||||||
|
Loading…
Reference in New Issue
Block a user