diff --git a/client/components/cards/ItemUploadCard.vue b/client/components/cards/ItemUploadCard.vue
index 21d97b20..68b77d56 100644
--- a/client/components/cards/ItemUploadCard.vue
+++ b/client/components/cards/ItemUploadCard.vue
@@ -8,6 +8,12 @@
close
+
+ refresh
+
+
{{ error }}
@@ -48,8 +54,8 @@
{{ $strings.MessageUploaderItemFailed }}
-
@@ -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 {
}
}
}
-
\ No newline at end of file
+
diff --git a/client/pages/upload/index.vue b/client/pages/upload/index.vue
index 09a9008b..bf3cf584 100644
--- a/client/pages/upload/index.vue
+++ b/client/pages/upload/index.vue
@@ -14,6 +14,14 @@
+
+
+
{{ $strings.LabelAutoFetchMetadata }}
+
+
+
+
+
{{ error }}
@@ -61,9 +69,16 @@
-
-
-
+
@@ -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)
}
}
-
\ No newline at end of file
+
diff --git a/client/strings/en-us.json b/client/strings/en-us.json
index 6f06ca77..9c608e48 100644
--- a/client/strings/en-us.json
+++ b/client/strings/en-us.json
@@ -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"
-}
\ No newline at end of file
+}