mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2026-07-06 17:31:41 +00:00
Fix: Handle database merge and redirect during consolidation conflicts
This commit is contained in:
parent
38d43c0163
commit
3ba2551ba1
2 changed files with 92 additions and 11 deletions
|
|
@ -627,9 +627,16 @@ export default {
|
||||||
this.processingConsolidationConflict = true
|
this.processingConsolidationConflict = true
|
||||||
const axios = this.$axios || this.$nuxt.$axios
|
const axios = this.$axios || this.$nuxt.$axios
|
||||||
try {
|
try {
|
||||||
await axios.$post(`/api/items/${this.consolidationConflictItem.id}/consolidate`, payload)
|
const data = await axios.$post(`/api/items/${this.consolidationConflictItem.id}/consolidate`, payload)
|
||||||
this.$toast.success(this.$strings.ToastConsolidateSuccess || 'Consolidation successful')
|
this.$toast.success(this.$strings.ToastConsolidateSuccess || 'Consolidation successful')
|
||||||
this.showConsolidationConflictModal = false
|
this.showConsolidationConflictModal = false
|
||||||
|
|
||||||
|
if (data.mergedInto) {
|
||||||
|
const id = data.mergedInto
|
||||||
|
if (this.$route.name.startsWith('item') && this.$route.params.id === this.consolidationConflictItem.id) {
|
||||||
|
this.$router.push(`/item/${id}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to resolve consolidation conflict', error)
|
console.error('Failed to resolve consolidation conflict', error)
|
||||||
this.$toast.error(error.response?.data?.error || error.response?.data || 'Failed to resolve conflict')
|
this.$toast.error(error.response?.data?.error || error.response?.data || 'Failed to resolve conflict')
|
||||||
|
|
|
||||||
|
|
@ -1728,25 +1728,61 @@ class LibraryItemController {
|
||||||
const expectedPath = Path.join(targetFolder.path, targetFolderName)
|
const expectedPath = Path.join(targetFolder.path, targetFolderName)
|
||||||
const isSamePath = req.libraryItem.path === expectedPath
|
const isSamePath = req.libraryItem.path === expectedPath
|
||||||
|
|
||||||
if (!isSamePath && !merge && (await fs.pathExists(expectedPath))) {
|
let existingItem = null
|
||||||
|
if (!isSamePath && (await fs.pathExists(expectedPath))) {
|
||||||
// Find existing library item at this path if any
|
// Find existing library item at this path if any
|
||||||
const existingItem = await Database.libraryItemModel.findOne({
|
existingItem = await Database.libraryItemModel.findOne({
|
||||||
where: {
|
where: {
|
||||||
path: expectedPath
|
path: expectedPath
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return res.status(409).json({
|
|
||||||
error: 'Destination already exists',
|
if (!merge) {
|
||||||
path: expectedPath,
|
return res.status(409).json({
|
||||||
existingLibraryItemId: existingItem?.id || null
|
error: 'Destination already exists',
|
||||||
})
|
path: expectedPath,
|
||||||
|
existingLibraryItemId: existingItem?.id || null
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
const oldPath = req.libraryItem.path
|
||||||
await handleMoveLibraryItem(req.libraryItem, library, targetFolder, targetFolderName, !!merge)
|
await handleMoveLibraryItem(req.libraryItem, library, targetFolder, targetFolderName, !!merge)
|
||||||
|
|
||||||
// Recursively remove empty parent directories
|
if (merge && existingItem) {
|
||||||
let parentDir = Path.dirname(req.libraryItem.path)
|
Logger.info(`[LibraryItemController] Consolidated item "${req.libraryItem.id}" was merged into existing item "${existingItem.id}"`)
|
||||||
|
|
||||||
|
const authorIds = req.libraryItem.media.authors?.map((au) => au.id) || []
|
||||||
|
const seriesIds = req.libraryItem.media.series?.map((se) => se.id) || []
|
||||||
|
|
||||||
|
// Cleanup associations for the item being absorbed
|
||||||
|
await this.handleDeleteLibraryItem(req.libraryItem.id, [req.libraryItem.media.id])
|
||||||
|
|
||||||
|
// Delete the redundant database record
|
||||||
|
await req.libraryItem.destroy()
|
||||||
|
|
||||||
|
if (authorIds.length) {
|
||||||
|
await this.checkRemoveAuthorsWithNoBooks(authorIds)
|
||||||
|
}
|
||||||
|
if (seriesIds.length) {
|
||||||
|
await this.checkRemoveEmptySeries(seriesIds)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rescan target item to pick up merged files
|
||||||
|
await LibraryItemScanner.scanLibraryItem(existingItem.id)
|
||||||
|
|
||||||
|
const updatedExistingItem = await Database.libraryItemModel.findByPkExpanded(existingItem.id)
|
||||||
|
|
||||||
|
return res.json({
|
||||||
|
success: true,
|
||||||
|
mergedInto: existingItem.id,
|
||||||
|
libraryItem: updatedExistingItem.toOldJSONExpanded()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recursively remove empty parent directories from original location
|
||||||
|
let parentDir = Path.dirname(oldPath)
|
||||||
while (parentDir && parentDir !== targetFolder.path && parentDir !== Path.dirname(parentDir)) {
|
while (parentDir && parentDir !== targetFolder.path && parentDir !== Path.dirname(parentDir)) {
|
||||||
try {
|
try {
|
||||||
const files = await fs.readdir(parentDir)
|
const files = await fs.readdir(parentDir)
|
||||||
|
|
@ -1805,10 +1841,48 @@ class LibraryItemController {
|
||||||
const library = await Database.libraryModel.findByIdWithFolders(libraryItem.libraryId)
|
const library = await Database.libraryModel.findByIdWithFolders(libraryItem.libraryId)
|
||||||
const currentLibraryFolder = library.libraryFolders.find((lf) => libraryItem.path.startsWith(lf.path)) || library.libraryFolders[0]
|
const currentLibraryFolder = library.libraryFolders.find((lf) => libraryItem.path.startsWith(lf.path)) || library.libraryFolders[0]
|
||||||
|
|
||||||
|
const targetPath = Path.join(currentLibraryFolder.path, sanitizedFolderName)
|
||||||
|
const isSamePath = libraryItem.path === targetPath
|
||||||
|
|
||||||
|
let existingItem = null
|
||||||
|
if (!isSamePath && (await fs.pathExists(targetPath))) {
|
||||||
|
existingItem = await Database.libraryItemModel.findOne({
|
||||||
|
where: { path: targetPath }
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!merge) {
|
||||||
|
results.push({ id: libraryItem.id, success: false, error: 'Destination already exists' })
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const oldPath = libraryItem.path
|
const oldPath = libraryItem.path
|
||||||
await handleMoveLibraryItem(libraryItem, library, currentLibraryFolder, sanitizedFolderName, !!merge)
|
await handleMoveLibraryItem(libraryItem, library, currentLibraryFolder, sanitizedFolderName, !!merge)
|
||||||
|
|
||||||
// Recursively remove empty parent directories
|
if (merge && existingItem) {
|
||||||
|
Logger.info(`[LibraryItemController] Batch Consolidate: Merging item "${libraryItem.id}" into existing item "${existingItem.id}"`)
|
||||||
|
|
||||||
|
const authorIds = libraryItem.media.authors?.map((au) => au.id) || []
|
||||||
|
const seriesIds = libraryItem.media.series?.map((se) => se.id) || []
|
||||||
|
|
||||||
|
await this.handleDeleteLibraryItem(libraryItem.id, [libraryItem.media.id])
|
||||||
|
await libraryItem.destroy()
|
||||||
|
|
||||||
|
if (authorIds.length) {
|
||||||
|
await this.checkRemoveAuthorsWithNoBooks(authorIds)
|
||||||
|
}
|
||||||
|
if (seriesIds.length) {
|
||||||
|
await this.checkRemoveEmptySeries(seriesIds)
|
||||||
|
}
|
||||||
|
|
||||||
|
await LibraryItemScanner.scanLibraryItem(existingItem.id)
|
||||||
|
|
||||||
|
results.push({ id: libraryItem.id, success: true, mergedInto: existingItem.id })
|
||||||
|
numSuccess++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recursively remove empty parent directories from original location
|
||||||
let parentDir = Path.dirname(oldPath)
|
let parentDir = Path.dirname(oldPath)
|
||||||
while (parentDir && parentDir !== currentLibraryFolder.path && parentDir !== Path.dirname(parentDir)) {
|
while (parentDir && parentDir !== currentLibraryFolder.path && parentDir !== Path.dirname(parentDir)) {
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue