2021-08-18 00:01:11 +02:00
|
|
|
<template>
|
2021-09-06 21:13:01 +02:00
|
|
|
<div class="w-full h-full relative">
|
2021-09-06 23:11:37 +02:00
|
|
|
<form class="w-full h-full" @submit.prevent="submitForm">
|
|
|
|
<div ref="formWrapper" class="px-4 py-6 details-form-wrapper w-full overflow-hidden overflow-y-auto">
|
|
|
|
<!-- <div v-if="userProgress" class="bg-success bg-opacity-40 rounded-md w-full px-4 py-1 mb-4 border border-success border-opacity-50">
|
2021-09-06 21:13:01 +02:00
|
|
|
<div class="w-full flex items-center">
|
|
|
|
<p>
|
|
|
|
Your progress: <span class="font-mono text-lg">{{ (userProgress * 100).toFixed(0) }}%</span>
|
|
|
|
</p>
|
|
|
|
<div class="flex-grow" />
|
|
|
|
<ui-btn v-if="!resettingProgress" small :padding-x="2" class="-mr-3" @click="resetProgress">Reset</ui-btn>
|
|
|
|
</div>
|
|
|
|
</div> -->
|
2021-09-06 23:11:37 +02:00
|
|
|
|
2021-09-06 21:13:01 +02:00
|
|
|
<ui-text-input-with-label v-model="details.title" label="Title" />
|
2021-08-18 00:01:11 +02:00
|
|
|
|
2021-09-06 21:13:01 +02:00
|
|
|
<ui-text-input-with-label v-model="details.subtitle" label="Subtitle" class="mt-2" />
|
2021-09-05 02:58:39 +02:00
|
|
|
|
2021-09-06 21:13:01 +02:00
|
|
|
<div class="flex mt-2 -mx-1">
|
|
|
|
<div class="w-3/4 px-1">
|
|
|
|
<ui-text-input-with-label v-model="details.author" label="Author" />
|
|
|
|
</div>
|
|
|
|
<div class="flex-grow px-1">
|
|
|
|
<ui-text-input-with-label v-model="details.publishYear" type="number" label="Publish Year" />
|
|
|
|
</div>
|
2021-08-20 02:14:24 +02:00
|
|
|
</div>
|
2021-08-18 00:01:11 +02:00
|
|
|
|
2021-09-06 21:13:01 +02:00
|
|
|
<div class="flex mt-2 -mx-1">
|
|
|
|
<div class="w-3/4 px-1">
|
|
|
|
<ui-input-dropdown v-model="details.series" label="Series" :items="series" />
|
|
|
|
</div>
|
|
|
|
<div class="flex-grow px-1">
|
|
|
|
<ui-text-input-with-label v-model="details.volumeNumber" label="Volume #" />
|
|
|
|
</div>
|
2021-08-25 03:24:40 +02:00
|
|
|
</div>
|
2021-08-19 18:31:03 +02:00
|
|
|
|
2021-09-06 21:13:01 +02:00
|
|
|
<ui-textarea-with-label v-model="details.description" :rows="3" label="Description" class="mt-2" />
|
2021-08-19 18:31:03 +02:00
|
|
|
|
2021-09-06 21:13:01 +02:00
|
|
|
<div class="flex mt-2 -mx-1">
|
|
|
|
<div class="w-1/2 px-1">
|
|
|
|
<ui-multi-select v-model="details.genres" label="Genres" :items="genres" />
|
|
|
|
</div>
|
|
|
|
<div class="flex-grow px-1">
|
|
|
|
<ui-multi-select v-model="newTags" label="Tags" :items="tags" />
|
|
|
|
</div>
|
2021-08-22 15:52:37 +02:00
|
|
|
</div>
|
2021-08-18 00:01:11 +02:00
|
|
|
|
2021-09-06 21:13:01 +02:00
|
|
|
<div class="flex mt-2 -mx-1">
|
|
|
|
<div class="w-1/2 px-1">
|
2021-10-07 04:08:52 +02:00
|
|
|
<ui-text-input-with-label v-model="details.narrator" label="Narrator" />
|
2021-09-06 21:13:01 +02:00
|
|
|
</div>
|
2021-09-05 02:58:39 +02:00
|
|
|
</div>
|
2021-09-06 23:11:37 +02:00
|
|
|
</div>
|
2021-09-05 02:58:39 +02:00
|
|
|
|
2021-09-06 23:11:37 +02:00
|
|
|
<div class="absolute bottom-0 left-0 w-full py-4 bg-bg" :class="isScrollable ? 'box-shadow-md-up' : 'box-shadow-sm-up border-t border-primary border-opacity-50'">
|
|
|
|
<div class="flex px-4">
|
2021-09-07 00:42:15 +02:00
|
|
|
<ui-btn v-if="userCanDelete" color="error" type="button" small @click.stop.prevent="deleteAudiobook">Remove</ui-btn>
|
2021-09-29 17:16:38 +02:00
|
|
|
|
2021-10-01 01:52:32 +02:00
|
|
|
<ui-tooltip text="(Root User Only) Save a NFO metadata file in your audiobooks directory" direction="bottom" class="ml-4">
|
2021-09-29 17:16:38 +02:00
|
|
|
<ui-btn v-if="isRootUser" :loading="savingMetadata" color="bg" type="button" class="h-full" small @click.stop.prevent="saveMetadata">Save Metadata</ui-btn>
|
|
|
|
</ui-tooltip>
|
|
|
|
|
2021-10-06 04:10:49 +02:00
|
|
|
<ui-tooltip :disabled="libraryScan" text="(Root User Only) Rescan audiobook including metadata" direction="bottom" class="ml-4">
|
|
|
|
<ui-btn v-if="isRootUser" :loading="rescanning" :disabled="libraryScan" color="bg" type="button" class="h-full" small @click.stop.prevent="rescan">Re-Scan</ui-btn>
|
2021-10-01 01:52:32 +02:00
|
|
|
</ui-tooltip>
|
|
|
|
|
2021-09-06 23:11:37 +02:00
|
|
|
<div class="flex-grow" />
|
|
|
|
<ui-btn type="submit">Submit</ui-btn>
|
|
|
|
</div>
|
2021-08-18 00:01:11 +02:00
|
|
|
</div>
|
2021-09-06 23:11:37 +02:00
|
|
|
</form>
|
2021-08-18 00:01:11 +02:00
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<script>
|
|
|
|
export default {
|
|
|
|
props: {
|
|
|
|
processing: Boolean,
|
|
|
|
audiobook: {
|
|
|
|
type: Object,
|
|
|
|
default: () => {}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
data() {
|
|
|
|
return {
|
|
|
|
details: {
|
|
|
|
title: null,
|
2021-09-05 02:58:39 +02:00
|
|
|
subtitle: null,
|
2021-08-18 00:01:11 +02:00
|
|
|
description: null,
|
2021-08-19 18:31:03 +02:00
|
|
|
author: null,
|
2021-10-07 04:08:52 +02:00
|
|
|
narrator: null,
|
2021-08-19 18:31:03 +02:00
|
|
|
series: null,
|
2021-08-25 03:24:40 +02:00
|
|
|
volumeNumber: null,
|
2021-08-20 02:14:24 +02:00
|
|
|
publishYear: null,
|
2021-08-20 00:29:36 +02:00
|
|
|
genres: []
|
2021-08-18 00:01:11 +02:00
|
|
|
},
|
2021-08-22 15:52:37 +02:00
|
|
|
newTags: [],
|
2021-09-06 21:13:01 +02:00
|
|
|
resettingProgress: false,
|
2021-09-29 17:16:38 +02:00
|
|
|
isScrollable: false,
|
2021-10-01 01:52:32 +02:00
|
|
|
savingMetadata: false,
|
|
|
|
rescanning: false
|
2021-08-18 00:01:11 +02:00
|
|
|
}
|
|
|
|
},
|
|
|
|
watch: {
|
|
|
|
audiobook: {
|
|
|
|
immediate: true,
|
|
|
|
handler(newVal) {
|
|
|
|
if (newVal) this.init()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
computed: {
|
|
|
|
isProcessing: {
|
|
|
|
get() {
|
|
|
|
return this.processing
|
|
|
|
},
|
|
|
|
set(val) {
|
|
|
|
this.$emit('update:processing', val)
|
|
|
|
}
|
|
|
|
},
|
2021-09-29 17:16:38 +02:00
|
|
|
isRootUser() {
|
|
|
|
return this.$store.getters['user/getIsRoot']
|
|
|
|
},
|
2021-08-18 00:01:11 +02:00
|
|
|
audiobookId() {
|
|
|
|
return this.audiobook ? this.audiobook.id : null
|
|
|
|
},
|
|
|
|
book() {
|
|
|
|
return this.audiobook ? this.audiobook.book || {} : {}
|
|
|
|
},
|
2021-09-07 00:42:15 +02:00
|
|
|
userCanDelete() {
|
|
|
|
return this.$store.getters['user/getUserCanDelete']
|
|
|
|
},
|
2021-08-22 15:52:37 +02:00
|
|
|
genres() {
|
|
|
|
return this.$store.state.audiobooks.genres
|
|
|
|
},
|
|
|
|
tags() {
|
|
|
|
return this.$store.state.audiobooks.tags
|
|
|
|
},
|
|
|
|
series() {
|
|
|
|
return this.$store.state.audiobooks.series
|
2021-10-06 04:10:49 +02:00
|
|
|
},
|
|
|
|
libraryId() {
|
|
|
|
return this.audiobook ? this.audiobook.libraryId : null
|
|
|
|
},
|
|
|
|
libraryScan() {
|
|
|
|
if (!this.libraryId) return null
|
|
|
|
return this.$store.getters['scanners/getLibraryScan'](this.libraryId)
|
2021-08-18 00:01:11 +02:00
|
|
|
}
|
|
|
|
},
|
|
|
|
methods: {
|
2021-10-01 01:52:32 +02:00
|
|
|
audiobookScanComplete(result) {
|
|
|
|
this.rescanning = false
|
|
|
|
if (!result) {
|
|
|
|
this.$toast.error(`Re-Scan Failed for "${this.title}"`)
|
|
|
|
} else if (result === 'UPDATED') {
|
|
|
|
this.$toast.success(`Re-Scan complete audiobook was updated`)
|
|
|
|
} else if (result === 'UPTODATE') {
|
|
|
|
this.$toast.success(`Re-Scan complete audiobook was up to date`)
|
|
|
|
} else if (result === 'REMOVED') {
|
|
|
|
this.$toast.error(`Re-Scan complete audiobook was removed`)
|
|
|
|
}
|
|
|
|
},
|
|
|
|
rescan() {
|
|
|
|
this.rescanning = true
|
|
|
|
this.$root.socket.once('audiobook_scan_complete', this.audiobookScanComplete)
|
|
|
|
this.$root.socket.emit('scan_audiobook', this.audiobookId)
|
|
|
|
},
|
2021-09-29 17:16:38 +02:00
|
|
|
saveMetadataComplete(result) {
|
|
|
|
this.savingMetadata = false
|
|
|
|
if (result.error) {
|
|
|
|
this.$toast.error(result.error)
|
|
|
|
} else if (result.audiobookId) {
|
|
|
|
var { savedPath } = result
|
|
|
|
if (!savedPath) {
|
|
|
|
this.$toast.error(`Failed to save metadata file (${result.audiobookId})`)
|
|
|
|
} else {
|
|
|
|
this.$toast.success(`Metadata file saved "${result.audiobookTitle}"`)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
saveMetadata() {
|
|
|
|
this.savingMetadata = true
|
|
|
|
this.$root.socket.once('save_metadata_complete', this.saveMetadataComplete)
|
|
|
|
this.$root.socket.emit('save_metadata', this.audiobookId)
|
|
|
|
},
|
2021-08-18 00:01:11 +02:00
|
|
|
async submitForm() {
|
2021-08-25 13:38:32 +02:00
|
|
|
if (this.isProcessing) {
|
|
|
|
return
|
|
|
|
}
|
2021-08-18 00:01:11 +02:00
|
|
|
this.isProcessing = true
|
|
|
|
const updatePayload = {
|
2021-08-22 15:52:37 +02:00
|
|
|
book: this.details,
|
|
|
|
tags: this.newTags
|
2021-08-18 00:01:11 +02:00
|
|
|
}
|
2021-08-22 15:52:37 +02:00
|
|
|
|
2021-08-18 00:01:11 +02:00
|
|
|
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) {
|
|
|
|
this.$toast.success('Update Successful')
|
|
|
|
this.$emit('close')
|
|
|
|
}
|
|
|
|
},
|
|
|
|
init() {
|
|
|
|
this.details.title = this.book.title
|
2021-09-05 02:58:39 +02:00
|
|
|
this.details.subtitle = this.book.subtitle
|
2021-08-18 00:01:11 +02:00
|
|
|
this.details.description = this.book.description
|
|
|
|
this.details.author = this.book.author
|
2021-10-07 04:08:52 +02:00
|
|
|
this.details.narrator = this.book.narrator
|
2021-08-20 00:29:36 +02:00
|
|
|
this.details.genres = this.book.genres || []
|
2021-08-19 18:31:03 +02:00
|
|
|
this.details.series = this.book.series
|
2021-08-25 03:24:40 +02:00
|
|
|
this.details.volumeNumber = this.book.volumeNumber
|
2021-08-20 02:14:24 +02:00
|
|
|
this.details.publishYear = this.book.publishYear
|
2021-08-22 15:52:37 +02:00
|
|
|
|
|
|
|
this.newTags = this.audiobook.tags || []
|
2021-08-18 00:01:11 +02:00
|
|
|
},
|
|
|
|
resetProgress() {
|
|
|
|
if (confirm(`Are you sure you want to reset your progress?`)) {
|
|
|
|
this.resettingProgress = true
|
|
|
|
this.$axios
|
|
|
|
.$delete(`/api/user/audiobook/${this.audiobookId}`)
|
|
|
|
.then(() => {
|
|
|
|
console.log('Progress reset complete')
|
|
|
|
this.$toast.success(`Your progress was reset`)
|
|
|
|
this.resettingProgress = false
|
|
|
|
})
|
|
|
|
.catch((error) => {
|
|
|
|
console.error('Progress reset failed', error)
|
|
|
|
this.resettingProgress = false
|
|
|
|
})
|
|
|
|
}
|
|
|
|
},
|
|
|
|
deleteAudiobook() {
|
2021-09-08 16:15:54 +02:00
|
|
|
if (confirm(`Are you sure you want to remove this audiobook?\n\n*Does not delete your files, only removes the audiobook from AudioBookshelf`)) {
|
2021-08-18 00:01:11 +02:00
|
|
|
this.isProcessing = true
|
|
|
|
this.$axios
|
|
|
|
.$delete(`/api/audiobook/${this.audiobookId}`)
|
|
|
|
.then(() => {
|
|
|
|
console.log('Audiobook removed')
|
|
|
|
this.$toast.success('Audiobook Removed')
|
|
|
|
this.$emit('close')
|
|
|
|
this.isProcessing = false
|
|
|
|
})
|
|
|
|
.catch((error) => {
|
|
|
|
console.error('Remove Audiobook failed', error)
|
|
|
|
this.isProcessing = false
|
|
|
|
})
|
|
|
|
}
|
2021-09-06 21:13:01 +02:00
|
|
|
},
|
|
|
|
checkIsScrollable() {
|
|
|
|
this.$nextTick(() => {
|
|
|
|
if (this.$refs.formWrapper) {
|
|
|
|
if (this.$refs.formWrapper.scrollHeight > this.$refs.formWrapper.clientHeight) {
|
|
|
|
this.isScrollable = true
|
|
|
|
} else {
|
|
|
|
this.isScrollable = false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
},
|
|
|
|
setResizeObserver() {
|
|
|
|
try {
|
|
|
|
this.$nextTick(() => {
|
|
|
|
const resizeObserver = new ResizeObserver(() => {
|
|
|
|
this.checkIsScrollable()
|
|
|
|
})
|
|
|
|
resizeObserver.observe(this.$refs.formWrapper)
|
|
|
|
})
|
|
|
|
} catch (error) {
|
|
|
|
console.error('Failed to set resize observer')
|
|
|
|
}
|
2021-08-18 00:01:11 +02:00
|
|
|
}
|
2021-09-06 21:13:01 +02:00
|
|
|
},
|
|
|
|
mounted() {
|
|
|
|
// this.init()
|
|
|
|
this.setResizeObserver()
|
2021-08-18 00:01:11 +02:00
|
|
|
}
|
|
|
|
}
|
2021-09-06 21:13:01 +02:00
|
|
|
</script>
|
|
|
|
|
|
|
|
<style scoped>
|
|
|
|
.details-form-wrapper {
|
|
|
|
height: calc(100% - 70px);
|
2021-09-06 23:11:37 +02:00
|
|
|
max-height: calc(100% - 70px);
|
2021-09-06 21:13:01 +02:00
|
|
|
}
|
|
|
|
</style>
|