mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2025-07-24 21:04:33 +02:00
Add db migration file to change audiobooks to library items with new data model
This commit is contained in:
parent
65793f7109
commit
b97ed953f7
17 changed files with 719 additions and 127 deletions
210
server/utils/dbMigration.js
Normal file
210
server/utils/dbMigration.js
Normal file
|
@ -0,0 +1,210 @@
|
|||
const Path = require('path')
|
||||
const fs = require('fs-extra')
|
||||
const njodb = require("njodb")
|
||||
|
||||
const { SupportedEbookTypes } = require('./globals')
|
||||
const Audiobook = require('../objects/Audiobook')
|
||||
const LibraryItem = require('../objects/LibraryItem')
|
||||
|
||||
const Logger = require('../Logger')
|
||||
const Book = require('../objects/entities/Book')
|
||||
const BookMetadata = require('../objects/metadata/BookMetadata')
|
||||
const Author = require('../objects/entities/Author')
|
||||
const Series = require('../objects/entities/Series')
|
||||
const AudioFile = require('../objects/files/AudioFile')
|
||||
const EBookFile = require('../objects/files/EBookFile')
|
||||
const LibraryFile = require('../objects/files/LibraryFile')
|
||||
const FileMetadata = require('../objects/metadata/FileMetadata')
|
||||
const AudioMetaTags = require('../objects/metadata/AudioMetaTags')
|
||||
|
||||
var authorsToAdd = []
|
||||
var seriesToAdd = []
|
||||
|
||||
// Load old audiobooks
|
||||
async function loadAudiobooks() {
|
||||
var audiobookPath = Path.join(global.ConfigPath, 'audiobooks')
|
||||
|
||||
var pathExists = await fs.pathExists(audiobookPath)
|
||||
if (!pathExists) {
|
||||
return []
|
||||
}
|
||||
|
||||
var audiobooksDb = new njodb.Database(audiobookPath)
|
||||
return audiobooksDb.select(() => true).then((results) => {
|
||||
return results.data.map(a => new Audiobook(a))
|
||||
})
|
||||
}
|
||||
|
||||
function makeAuthorsFromOldAb(authorsList) {
|
||||
return authorsList.filter(a => !!a).map(authorName => {
|
||||
var existingAuthor = authorsToAdd.find(a => a.name.toLowerCase() === authorName.toLowerCase())
|
||||
if (existingAuthor) {
|
||||
return existingAuthor.toJSONMinimal()
|
||||
}
|
||||
|
||||
var newAuthor = new Author()
|
||||
newAuthor.setData({ name: authorName })
|
||||
authorsToAdd.push(newAuthor)
|
||||
Logger.info(`>>> Created new author named "${authorName}"`)
|
||||
return newAuthor.toJSONMinimal()
|
||||
})
|
||||
}
|
||||
|
||||
function makeSeriesFromOldAb({ series, volumeNumber }) {
|
||||
var existingSeries = seriesToAdd.find(s => s.name.toLowerCase() === series.toLowerCase())
|
||||
if (existingSeries) {
|
||||
return [existingSeries.toJSONMinimal(volumeNumber)]
|
||||
}
|
||||
var newSeries = new Series()
|
||||
newSeries.setData({ name: series })
|
||||
seriesToAdd.push(newSeries)
|
||||
Logger.info(`>>> Created new series named "${series}"`)
|
||||
return [newSeries.toJSONMinimal(volumeNumber)]
|
||||
}
|
||||
|
||||
function getRelativePath(srcPath, basePath) {
|
||||
srcPath = srcPath.replace(/\\/g, '/')
|
||||
basePath = basePath.replace(/\\/g, '/')
|
||||
if (basePath.endsWith('/')) basePath = basePath.slice(0, -1)
|
||||
return srcPath.replace(basePath, '')
|
||||
}
|
||||
|
||||
function makeFilesFromOldAb(audiobook) {
|
||||
var libraryFiles = []
|
||||
var ebookFiles = []
|
||||
|
||||
var audioFiles = audiobook._audioFiles.map((af) => {
|
||||
var fileMetadata = new FileMetadata(af)
|
||||
fileMetadata.path = af.fullPath
|
||||
fileMetadata.relPath = getRelativePath(af.fullPath, audiobook.fullPath)
|
||||
|
||||
var newLibraryFile = new LibraryFile()
|
||||
newLibraryFile.ino = af.ino
|
||||
newLibraryFile.metadata = fileMetadata.clone()
|
||||
newLibraryFile.addedAt = af.addedAt
|
||||
newLibraryFile.updatedAt = Date.now()
|
||||
libraryFiles.push(newLibraryFile)
|
||||
|
||||
var audioMetaTags = new AudioMetaTags(af.metadata || {}) // Old metaTags was named metadata
|
||||
delete af.metadata
|
||||
|
||||
var newAudioFile = new AudioFile(af)
|
||||
newAudioFile.metadata = fileMetadata
|
||||
newAudioFile.metaTags = audioMetaTags
|
||||
newAudioFile.updatedAt = Date.now()
|
||||
return newAudioFile
|
||||
})
|
||||
|
||||
audiobook._otherFiles.forEach((file) => {
|
||||
var fileMetadata = new FileMetadata(file)
|
||||
fileMetadata.path = file.fullPath
|
||||
fileMetadata.relPath = getRelativePath(file.fullPath, audiobook.fullPath)
|
||||
|
||||
var newLibraryFile = new LibraryFile()
|
||||
newLibraryFile.ino = file.ino
|
||||
newLibraryFile.metadata = fileMetadata.clone()
|
||||
newLibraryFile.addedAt = file.addedAt
|
||||
newLibraryFile.updatedAt = Date.now()
|
||||
libraryFiles.push(newLibraryFile)
|
||||
|
||||
var formatExt = (file.ext || '').slice(1)
|
||||
if (SupportedEbookTypes.includes(formatExt)) {
|
||||
var newEBookFile = new EBookFile()
|
||||
newEBookFile.ino = file.ino
|
||||
newEBookFile.metadata = fileMetadata
|
||||
newEBookFile.ebookFormat = formatExt
|
||||
newEBookFile.addedAt = file.addedAt
|
||||
newEBookFile.updatedAt = Date.now()
|
||||
ebookFiles.push(newEBookFile)
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
libraryFiles,
|
||||
ebookFiles,
|
||||
audioFiles
|
||||
}
|
||||
}
|
||||
|
||||
function makeLibraryItemFromOldAb(audiobook) {
|
||||
var libraryItem = new LibraryItem()
|
||||
libraryItem.id = audiobook.id
|
||||
libraryItem.ino = audiobook.ino
|
||||
libraryItem.libraryId = audiobook.libraryId
|
||||
libraryItem.folderId = audiobook.folderId
|
||||
libraryItem.path = audiobook.fullPath
|
||||
libraryItem.relPath = audiobook.path
|
||||
libraryItem.mtimeMs = audiobook.mtimeMs || 0
|
||||
libraryItem.ctimeMs = audiobook.ctimeMs || 0
|
||||
libraryItem.birthtimeMs = audiobook.birthtimeMs || 0
|
||||
libraryItem.addedAt = audiobook.addedAt
|
||||
libraryItem.lastUpdate = audiobook.lastUpdate
|
||||
libraryItem.lastScan = audiobook.lastScan
|
||||
libraryItem.scanVersion = audiobook.scanVersion
|
||||
libraryItem.isMissing = audiobook.isMissing
|
||||
libraryItem.entityType = 'book'
|
||||
|
||||
var bookEntity = new Book()
|
||||
var bookMetadata = new BookMetadata(audiobook.book)
|
||||
if (audiobook.book.narrator) {
|
||||
bookMetadata.narrators = audiobook.book._narratorsList
|
||||
}
|
||||
// Returns array of json minimal authors
|
||||
bookMetadata.authors = makeAuthorsFromOldAb(audiobook.book._authorsList)
|
||||
|
||||
// Returns array of json minimal series
|
||||
if (audiobook.book.series) {
|
||||
bookMetadata.series = makeSeriesFromOldAb(audiobook.book)
|
||||
}
|
||||
|
||||
bookEntity.metadata = bookMetadata
|
||||
bookEntity.coverPath = audiobook.book.coverFullPath
|
||||
// Path relative to library item
|
||||
bookEntity.relCoverPath = getRelativePath(audiobook.book.coverFullPath, audiobook.fullPath)
|
||||
bookEntity.tags = [...audiobook.tags]
|
||||
|
||||
var payload = makeFilesFromOldAb(audiobook)
|
||||
bookEntity.audioFiles = payload.audioFiles
|
||||
bookEntity.ebookFiles = payload.ebookFiles
|
||||
|
||||
if (audiobook.chapters && audiobook.chapters.length) {
|
||||
bookEntity.chapters = audiobook.chapters.map(c => ({ ...c }))
|
||||
}
|
||||
|
||||
libraryItem.entity = bookEntity
|
||||
libraryItem.libraryFiles = payload.libraryFiles
|
||||
return libraryItem
|
||||
}
|
||||
|
||||
async function migrateDb(db) {
|
||||
Logger.info(`==== Starting DB Migration ====`)
|
||||
|
||||
var audiobooks = await loadAudiobooks()
|
||||
if (!audiobooks.length) {
|
||||
Logger.info(`>>> No audiobooks in db, no migration necessary`)
|
||||
return
|
||||
}
|
||||
|
||||
Logger.info(`>>> Loaded old audiobook data with ${audiobooks.length} records`)
|
||||
|
||||
if (db.libraryItems.length) {
|
||||
Logger.info(`>>> Some library items already loaded ${db.libraryItems.length} items | ${db.series.length} series | ${db.authors.length} authors`)
|
||||
return
|
||||
}
|
||||
|
||||
var libraryItems = audiobooks.map((ab) => makeLibraryItemFromOldAb(ab))
|
||||
|
||||
Logger.info(`>>> ${libraryItems.length} Library Items made`)
|
||||
await db.insertEntities('libraryItem', libraryItems)
|
||||
if (authorsToAdd.length) {
|
||||
Logger.info(`>>> ${authorsToAdd.length} Authors made`)
|
||||
await db.insertEntities('author', authorsToAdd)
|
||||
}
|
||||
if (seriesToAdd.length) {
|
||||
Logger.info(`>>> ${seriesToAdd.length} Series made`)
|
||||
await db.insertEntities('series', seriesToAdd)
|
||||
}
|
||||
|
||||
Logger.info(`==== DB Migration Complete ====`)
|
||||
}
|
||||
module.exports = migrateDb
|
Loading…
Add table
Add a link
Reference in a new issue