mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2026-03-04 06:59:41 +00:00
feat: add UI for editing series Audible ASIN
- Create AsinInput.vue component for ASIN input with URL extraction - Update EditSeriesInputInnerModal to include ASIN field - Update SeriesInputWidget to fetch and save ASIN data - Add SeriesController PATCH endpoint for updating ASIN - Add localization strings for ASIN-related messages The AsinInput component automatically extracts ASINs from pasted Audible URLs and provides validation feedback.
This commit is contained in:
parent
40606eb1af
commit
b8b3a20498
9 changed files with 322 additions and 16 deletions
|
|
@ -14,6 +14,16 @@
|
|||
<ui-text-input-with-label ref="sequenceInput" v-model="selectedSeries.sequence" :label="$strings.LabelSequence" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex mt-2">
|
||||
<div class="grow p-1">
|
||||
<div class="flex items-center">
|
||||
<ui-asin-input ref="asinInput" v-model="seriesAsin" :label="$strings.LabelSeriesAsin" :extracted-message="$strings.MessageAsinExtractedFromUrl" :valid-message="$strings.MessageValidAsinFormat" :invalid-message="$strings.MessageInvalidAsin" class="flex-grow" />
|
||||
<ui-tooltip :text="$strings.MessageAsinCheck" direction="top" class="ml-2 mt-5">
|
||||
<span class="material-symbols text-gray-400 hover:text-white cursor-help" style="font-size: 1.1rem">help</span>
|
||||
</ui-tooltip>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="error" class="text-error text-sm mt-2 p-1">{{ error }}</div>
|
||||
<div class="flex justify-end mt-2 p-1">
|
||||
<ui-btn type="submit">{{ $strings.ButtonSubmit }}</ui-btn>
|
||||
|
|
@ -45,7 +55,8 @@ export default {
|
|||
return {
|
||||
el: null,
|
||||
content: null,
|
||||
error: null
|
||||
error: null,
|
||||
seriesAsin: ''
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
|
|
@ -55,6 +66,21 @@ export default {
|
|||
} else {
|
||||
this.setHide()
|
||||
}
|
||||
},
|
||||
selectedSeries: {
|
||||
handler(newVal) {
|
||||
if (!this.show) return
|
||||
this.seriesAsin = newVal?.audibleSeriesAsin || ''
|
||||
},
|
||||
deep: true
|
||||
},
|
||||
// Watch for series name changes to auto-populate ASIN when selecting existing series
|
||||
'selectedSeries.name': {
|
||||
async handler(newName) {
|
||||
if (!this.show || !newName || !this.isNewSeries) return
|
||||
// Check if this matches an existing series in the library
|
||||
await this.fetchSeriesAsinByName(newName)
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
|
@ -77,6 +103,22 @@ export default {
|
|||
this.$refs.sequenceInput.setFocus()
|
||||
}
|
||||
},
|
||||
async fetchSeriesAsinByName(seriesName) {
|
||||
try {
|
||||
const libraryId = this.$store.state.libraries.currentLibraryId
|
||||
const series = this.$store.state.libraries.filterData?.series || []
|
||||
const matchingSeries = series.find((se) => se.name.toLowerCase() === seriesName.toLowerCase())
|
||||
if (!matchingSeries) return
|
||||
|
||||
// Fetch full series data to get ASIN
|
||||
const fullSeries = await this.$axios.$get(`/api/libraries/${libraryId}/series/${matchingSeries.id}`)
|
||||
if (fullSeries?.audibleSeriesAsin) {
|
||||
this.seriesAsin = fullSeries.audibleSeriesAsin
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch series ASIN:', error)
|
||||
}
|
||||
},
|
||||
setInputFocus() {
|
||||
if (this.isNewSeries) {
|
||||
// Focus on series input if new series
|
||||
|
|
@ -102,7 +144,18 @@ export default {
|
|||
return
|
||||
}
|
||||
|
||||
this.$emit('submit')
|
||||
// Validate ASIN format if provided
|
||||
if (this.seriesAsin && this.seriesAsin.trim()) {
|
||||
const asin = this.seriesAsin.trim().toUpperCase()
|
||||
if (!/^[A-Z0-9]{10}$/.test(asin)) {
|
||||
this.error = this.$strings.MessageInvalidAsin
|
||||
return
|
||||
}
|
||||
this.seriesAsin = asin
|
||||
}
|
||||
|
||||
// Pass ASIN along with submit
|
||||
this.$emit('submit', { audibleSeriesAsin: this.seriesAsin || null })
|
||||
},
|
||||
clickClose() {
|
||||
this.show = false
|
||||
|
|
@ -114,6 +167,9 @@ export default {
|
|||
},
|
||||
setShow() {
|
||||
this.error = null
|
||||
// Load existing ASIN from the series if it exists
|
||||
this.seriesAsin = this.selectedSeries?.audibleSeriesAsin || ''
|
||||
|
||||
if (!this.el || !this.content) {
|
||||
this.init()
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue