audiobookshelf/client/components/modals/edit-tabs/Details.vue

238 lines
7.8 KiB
Vue
Raw Normal View History

2021-08-18 00:01:11 +02:00
<template>
<div class="w-full h-full relative">
<widgets-item-details-edit ref="itemDetailsEdit" :library-item="libraryItem" @submit="submitForm" />
<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 items-center px-4">
<ui-btn v-if="userCanDelete" color="error" type="button" class="h-8" :padding-x="3" small @click.stop.prevent="removeItem">Remove</ui-btn>
2021-08-18 00:01:11 +02:00
<div class="flex-grow" />
2021-08-19 18:31:03 +02:00
<ui-tooltip v-if="!isMissing" text="(Root User Only) Save a NFO metadata file in your audiobooks directory" direction="bottom" class="mr-4 hidden sm:block">
<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-08-19 18:31:03 +02:00
<ui-tooltip :disabled="!!quickMatching" :text="`(Root User Only) Populate empty book details & cover with first book result from '${libraryProvider}'. Does not overwrite details.`" direction="bottom" class="mr-4">
<ui-btn v-if="isRootUser" :loading="quickMatching" color="bg" type="button" class="h-full" small @click.stop.prevent="quickMatch">Quick Match</ui-btn>
</ui-tooltip>
2021-08-18 00:01:11 +02:00
<ui-tooltip :disabled="!!libraryScan" text="(Root User Only) Rescan audiobook including metadata" direction="bottom" class="mr-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>
</ui-tooltip>
<ui-btn @click="submitForm">Submit</ui-btn>
2021-09-06 23:11:37 +02:00
</div>
</div>
2021-08-18 00:01:11 +02:00
</div>
</template>
<script>
export default {
props: {
processing: Boolean,
libraryItem: {
2021-08-18 00:01:11 +02:00
type: Object,
default: () => {}
}
},
data() {
return {
resettingProgress: false,
isScrollable: false,
savingMetadata: false,
2022-02-15 23:15:09 +01:00
rescanning: false,
quickMatching: false
2021-08-18 00:01:11 +02:00
}
},
computed: {
isProcessing: {
get() {
return this.processing
},
set(val) {
this.$emit('update:processing', val)
}
},
isRootUser() {
return this.$store.getters['user/getIsRoot']
},
2021-10-27 00:55:48 +02:00
isMissing() {
return !!this.libraryItem && !!this.libraryItem.isMissing
2021-10-27 00:55:48 +02:00
},
libraryItemId() {
return this.libraryItem ? this.libraryItem.id : null
2021-08-18 00:01:11 +02:00
},
media() {
return this.libraryItem ? this.libraryItem.media || {} : {}
},
mediaMetadata() {
return this.media.metadata || {}
2021-08-18 00:01:11 +02:00
},
userCanDelete() {
return this.$store.getters['user/getUserCanDelete']
},
2021-10-06 04:10:49 +02:00
libraryId() {
return this.libraryItem ? this.libraryItem.libraryId : null
2021-10-06 04:10:49 +02:00
},
2022-02-15 23:15:09 +01:00
libraryProvider() {
return this.$store.getters['libraries/getLibraryProvider'](this.libraryId) || 'google'
},
2021-10-06 04:10:49 +02:00
libraryScan() {
if (!this.libraryId) return null
return this.$store.getters['scanners/getLibraryScan'](this.libraryId)
2021-08-18 00:01:11 +02:00
}
},
methods: {
2022-02-15 23:15:09 +01:00
quickMatch() {
if (this.quickMatching) return
if (!this.$refs.itemDetailsEdit) return
var { title, author } = this.$refs.itemDetailsEdit.getTitleAndAuthorName()
if (!title) {
this.$toast.error('Must have a title for quick match')
return
}
2022-02-15 23:15:09 +01:00
this.quickMatching = true
var matchOptions = {
provider: this.libraryProvider,
title: title || null,
author: author || null
2022-02-15 23:15:09 +01:00
}
this.$axios
.$post(`/api/items/${this.libraryItemId}/match`, matchOptions)
2022-02-15 23:15:09 +01:00
.then((res) => {
this.quickMatching = false
if (res.warning) {
this.$toast.warning(res.warning)
} else if (res.updated) {
this.$toast.success('Item details updated')
2022-02-15 23:15:09 +01:00
} else {
this.$toast.info('No updates were made')
}
})
.catch((error) => {
var errMsg = error.response ? error.response.data || '' : ''
console.error('Failed to match', error)
this.$toast.error(errMsg || 'Failed to match')
this.quickMatching = false
})
},
libraryScanComplete(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 item was updated`)
} else if (result === 'UPTODATE') {
this.$toast.success(`Re-Scan complete item was up to date`)
} else if (result === 'REMOVED') {
this.$toast.error(`Re-Scan complete item was removed`)
}
},
rescan() {
this.rescanning = true
this.$root.socket.once('item_scan_complete', this.libraryScanComplete)
this.$root.socket.emit('scan_item', this.libraryItemId)
},
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.libraryItemId)
},
2021-12-02 02:07:03 +01:00
submitForm() {
if (this.isProcessing) {
return
}
if (!this.$refs.itemDetailsEdit) {
return
2021-12-02 02:07:03 +01:00
}
var updatedDetails = this.$refs.itemDetailsEdit.getDetails()
if (!updatedDetails.hasChanges) {
this.$toast.info('No changes were made')
return
2021-12-02 02:07:03 +01:00
}
this.updateDetails(updatedDetails)
2021-12-02 02:07:03 +01:00
},
async updateDetails(updatedDetails) {
this.isProcessing = true
console.log('Sending update', updatedDetails.updatePayload)
var updatedAudiobook = await this.$axios.$patch(`/api/items/${this.libraryItemId}/media`, updatedDetails.updatePayload).catch((error) => {
2021-08-18 00:01:11 +02:00
console.error('Failed to update', error)
return false
})
this.isProcessing = false
if (updatedAudiobook) {
this.$toast.success('Update Successful')
this.$emit('close')
}
},
removeItem() {
if (confirm(`Are you sure you want to remove this item?\n\n*Does not delete your files, only removes the item from audiobookshelf`)) {
2021-08-18 00:01:11 +02:00
this.isProcessing = true
this.$axios
.$delete(`/api/items/${this.libraryItemId}`)
2021-08-18 00:01:11 +02:00
.then(() => {
console.log('Item removed')
this.$toast.success('Item Removed')
2021-08-18 00:01:11 +02:00
this.$emit('close')
this.isProcessing = false
})
.catch((error) => {
console.error('Remove item failed', error)
2021-08-18 00:01:11 +02:00
this.isProcessing = false
})
}
},
checkIsScrollable() {
this.$nextTick(() => {
var formWrapper = document.getElementById('formWrapper')
if (formWrapper) {
if (formWrapper.scrollHeight > formWrapper.clientHeight) {
this.isScrollable = true
} else {
this.isScrollable = false
}
}
})
},
setResizeObserver() {
try {
var formWrapper = document.getElementById('formWrapper')
if (formWrapper) {
this.$nextTick(() => {
const resizeObserver = new ResizeObserver(() => {
this.checkIsScrollable()
})
resizeObserver.observe(formWrapper)
})
}
} catch (error) {
console.error('Failed to set resize observer')
}
2021-08-18 00:01:11 +02:00
}
},
mounted() {
this.setResizeObserver()
2021-08-18 00:01:11 +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);
}
</style>