mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2025-01-22 00:07:52 +01:00
Adds fetching book data on upload
This commit is contained in:
parent
aa933df525
commit
3cc900ffbf
@ -8,6 +8,12 @@
|
||||
<span class="text-base text-white text-opacity-80 font-mono material-icons">close</span>
|
||||
</div>
|
||||
|
||||
<div v-if="!isPodcast"
|
||||
class="w-8 h-8 bg-bg border border-white border-opacity-10 flex items-center justify-center rounded-full hover:bg-primary cursor-pointer"
|
||||
@click="fetchMetadata">
|
||||
<span class="text-base text-white text-opacity-80 font-mono material-icons">refresh</span>
|
||||
</div>
|
||||
|
||||
<template v-if="!uploadSuccess && !uploadFailed">
|
||||
<widgets-alert v-if="error" type="error">
|
||||
<p class="text-base">{{ error }}</p>
|
||||
@ -48,8 +54,8 @@
|
||||
<p class="text-base">{{ $strings.MessageUploaderItemFailed }}</p>
|
||||
</widgets-alert>
|
||||
|
||||
<div v-if="isUploading" class="absolute top-0 left-0 w-full h-full bg-black bg-opacity-50 flex items-center justify-center z-20">
|
||||
<ui-loading-indicator :text="$strings.MessageUploading" />
|
||||
<div v-if="isNonInteractable" class="absolute top-0 left-0 w-full h-full bg-black bg-opacity-50 flex items-center justify-center z-20">
|
||||
<ui-loading-indicator :text="nonInteractionLabel" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@ -61,10 +67,11 @@ export default {
|
||||
props: {
|
||||
item: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
default: () => { }
|
||||
},
|
||||
mediaType: String,
|
||||
processing: Boolean
|
||||
processing: Boolean,
|
||||
provider: String
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@ -76,7 +83,8 @@ export default {
|
||||
error: '',
|
||||
isUploading: false,
|
||||
uploadFailed: false,
|
||||
uploadSuccess: false
|
||||
uploadSuccess: false,
|
||||
isFetchingMetadata: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@ -94,6 +102,16 @@ export default {
|
||||
} else {
|
||||
return this.itemData.title
|
||||
}
|
||||
},
|
||||
isNonInteractable() {
|
||||
return this.isUploading || this.isFetchingMetadata
|
||||
},
|
||||
nonInteractionLabel() {
|
||||
if (this.isUploading) {
|
||||
return this.$strings.MessageUploading
|
||||
} else if (this.isFetchingMetadata) {
|
||||
return this.$strings.LabelFetchingMetadata
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@ -105,6 +123,30 @@ export default {
|
||||
titleUpdated() {
|
||||
this.error = ''
|
||||
},
|
||||
async fetchMetadata() {
|
||||
if (!this.itemData.title.trim().length) {
|
||||
return
|
||||
}
|
||||
|
||||
this.isFetchingMetadata = true
|
||||
|
||||
try {
|
||||
const searchQueryString = `title=${this.itemData.title}&author=${this.itemData.author}&provider=${this.provider}`
|
||||
const [bestCandidate, ..._rest] = await this.$axios.$get(`/api/search/books?${searchQueryString}`)
|
||||
|
||||
this.itemData = {
|
||||
...this.itemData,
|
||||
title: bestCandidate?.title,
|
||||
author: bestCandidate?.author,
|
||||
series: (bestCandidate?.series || [])[0]?.series
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Failed', e)
|
||||
// TODO: do something with the error?
|
||||
} finally {
|
||||
this.isFetchingMetadata = false
|
||||
}
|
||||
},
|
||||
getData() {
|
||||
if (!this.itemData.title) {
|
||||
this.error = 'Must have a title'
|
||||
@ -128,4 +170,4 @@ export default {
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</script>
|
||||
|
@ -14,6 +14,14 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="!selectedLibraryIsPodcast" class="flex items-center py-2">
|
||||
<ui-toggle-switch v-model="fetchMetadata.enabled" />
|
||||
<p class="pl-4 text-base">{{ $strings.LabelAutoFetchMetadata }}</p>
|
||||
<div class="flex-grow ml-4">
|
||||
<ui-dropdown v-model="fetchMetadata.provider" :items="providers" :label="$strings.LabelProvider" :disabled="!fetchMetadata.enabled" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<widgets-alert v-if="error" type="error">
|
||||
<p class="text-lg">{{ error }}</p>
|
||||
</widgets-alert>
|
||||
@ -61,9 +69,16 @@
|
||||
</widgets-alert>
|
||||
|
||||
<!-- Item Upload cards -->
|
||||
<template v-for="item in items">
|
||||
<cards-item-upload-card :ref="`itemCard-${item.index}`" :key="item.index" :media-type="selectedLibraryMediaType" :item="item" :processing="processing" @remove="removeItem(item)" />
|
||||
</template>
|
||||
<cards-item-upload-card
|
||||
v-for="item in items"
|
||||
:key="item.index"
|
||||
:ref="`itemCard-${item.index}`"
|
||||
:media-type="selectedLibraryMediaType"
|
||||
:item="item"
|
||||
:provider="fetchMetadata.provider"
|
||||
:processing="processing"
|
||||
@remove="removeItem(item)"
|
||||
/>
|
||||
|
||||
<!-- Upload/Reset btns -->
|
||||
<div v-show="items.length" class="flex justify-end pb-8 pt-4">
|
||||
@ -92,13 +107,18 @@ export default {
|
||||
selectedLibraryId: null,
|
||||
selectedFolderId: null,
|
||||
processing: false,
|
||||
uploadFinished: false
|
||||
uploadFinished: false,
|
||||
fetchMetadata: {
|
||||
enabled: false,
|
||||
provider: 'google'
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
selectedLibrary(newVal) {
|
||||
if (newVal && !this.selectedFolderId) {
|
||||
this.setDefaultFolder()
|
||||
this.setMetadataProvider()
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -133,6 +153,13 @@ export default {
|
||||
selectedLibraryIsPodcast() {
|
||||
return this.selectedLibraryMediaType === 'podcast'
|
||||
},
|
||||
providers() {
|
||||
if (this.selectedLibraryIsPodcast) return this.$store.state.scanners.podcastProviders
|
||||
return this.$store.state.scanners.providers
|
||||
},
|
||||
canFetchMetadata() {
|
||||
return !this.selectedLibraryIsPodcast && this.fetchMetadata.enabled
|
||||
},
|
||||
selectedFolder() {
|
||||
if (!this.selectedLibrary) return null
|
||||
return this.selectedLibrary.folders.find((fold) => fold.id === this.selectedFolderId)
|
||||
@ -160,12 +187,16 @@ export default {
|
||||
}
|
||||
}
|
||||
this.setDefaultFolder()
|
||||
this.setMetadataProvider()
|
||||
},
|
||||
setDefaultFolder() {
|
||||
if (!this.selectedFolderId && this.selectedLibrary && this.selectedLibrary.folders.length) {
|
||||
this.selectedFolderId = this.selectedLibrary.folders[0].id
|
||||
}
|
||||
},
|
||||
setMetadataProvider() {
|
||||
this.fetchMetadata.provider = this.$store.getters['libraries/getLibraryProvider'](this.selectedLibraryId)
|
||||
},
|
||||
removeItem(item) {
|
||||
this.items = this.items.filter((b) => b.index !== item.index)
|
||||
if (!this.items.length) {
|
||||
@ -213,27 +244,49 @@ export default {
|
||||
var items = e.dataTransfer.items || []
|
||||
|
||||
var itemResults = await this.uploadHelpers.getItemsFromDrop(items, this.selectedLibraryMediaType)
|
||||
this.setResults(itemResults)
|
||||
this.onItemsSelected(itemResults)
|
||||
},
|
||||
inputChanged(e) {
|
||||
if (!e.target || !e.target.files) return
|
||||
var _files = Array.from(e.target.files)
|
||||
if (_files && _files.length) {
|
||||
var itemResults = this.uploadHelpers.getItemsFromPicker(_files, this.selectedLibraryMediaType)
|
||||
this.setResults(itemResults)
|
||||
this.onItemsSelected(itemResults)
|
||||
}
|
||||
},
|
||||
setResults(itemResults) {
|
||||
onItemsSelected(itemResults) {
|
||||
if (this.itemSelectionSuccessful(itemResults)) {
|
||||
// setTimeout ensures the new item ref is attached before this method is called
|
||||
setTimeout(this.attemptMetadataFetch, 0)
|
||||
}
|
||||
},
|
||||
itemSelectionSuccessful(itemResults) {
|
||||
console.log('Upload results', itemResults)
|
||||
|
||||
if (itemResults.error) {
|
||||
this.error = itemResults.error
|
||||
this.items = []
|
||||
this.ignoredFiles = []
|
||||
} else {
|
||||
this.error = ''
|
||||
this.items = itemResults.items
|
||||
this.ignoredFiles = itemResults.ignoredFiles
|
||||
return false
|
||||
}
|
||||
console.log('Upload results', itemResults)
|
||||
|
||||
this.error = ''
|
||||
this.items = itemResults.items
|
||||
this.ignoredFiles = itemResults.ignoredFiles
|
||||
return true
|
||||
},
|
||||
attemptMetadataFetch() {
|
||||
if (!this.canFetchMetadata) {
|
||||
return false
|
||||
}
|
||||
|
||||
this.items.forEach((item) => {
|
||||
let itemRef = this.$refs[`itemCard-${item.index}`]
|
||||
|
||||
if (itemRef?.length) {
|
||||
itemRef[0].fetchMetadata(this.fetchMetadata.provider)
|
||||
}
|
||||
})
|
||||
},
|
||||
updateItemCardStatus(index, status) {
|
||||
var ref = this.$refs[`itemCard-${index}`]
|
||||
@ -346,6 +399,8 @@ export default {
|
||||
},
|
||||
mounted() {
|
||||
this.selectedLibraryId = this.$store.state.libraries.currentLibraryId
|
||||
this.setMetadataProvider()
|
||||
|
||||
this.setDefaultFolder()
|
||||
window.addEventListener('dragenter', this.dragenter)
|
||||
window.addEventListener('dragleave', this.dragleave)
|
||||
@ -359,4 +414,4 @@ export default {
|
||||
window.removeEventListener('drop', this.drop)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</script>
|
||||
|
@ -194,6 +194,7 @@
|
||||
"LabelAuthorLastFirst": "Author (Last, First)",
|
||||
"LabelAuthors": "Authors",
|
||||
"LabelAutoDownloadEpisodes": "Auto Download Episodes",
|
||||
"LabelAutoFetchMetadata": "Auto Fetch Metadata",
|
||||
"LabelBackToUser": "Back to User",
|
||||
"LabelBackupLocation": "Backup Location",
|
||||
"LabelBackupsEnableAutomaticBackups": "Enable automatic backups",
|
||||
@ -259,6 +260,7 @@
|
||||
"LabelExample": "Example",
|
||||
"LabelExplicit": "Explicit",
|
||||
"LabelFeedURL": "Feed URL",
|
||||
"LabelFetchingMetadata": "Fetching Metadata",
|
||||
"LabelFile": "File",
|
||||
"LabelFileBirthtime": "File Birthtime",
|
||||
"LabelFileModified": "File Modified",
|
||||
@ -727,4 +729,4 @@
|
||||
"ToastSocketFailedToConnect": "Socket failed to connect",
|
||||
"ToastUserDeleteFailed": "Failed to delete user",
|
||||
"ToastUserDeleteSuccess": "User deleted"
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user