mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2025-08-02 01:05:25 +02:00
Support multi library 1.4.0
This commit is contained in:
parent
a65f7e6fad
commit
d9d34e87e0
29 changed files with 452 additions and 188 deletions
|
@ -118,6 +118,7 @@ class Audiobook {
|
|||
|
||||
get _audioFiles() { return this.audioFiles || [] }
|
||||
get _otherFiles() { return this.otherFiles || [] }
|
||||
get _tracks() { return this.tracks || [] }
|
||||
|
||||
get ebooks() {
|
||||
return this.otherFiles.filter(file => file.filetype === 'ebook')
|
||||
|
@ -128,13 +129,21 @@ class Audiobook {
|
|||
}
|
||||
|
||||
get hasMissingIno() {
|
||||
return !this.ino || this._audioFiles.find(abf => !abf.ino) || this._otherFiles.find(f => !f.ino) || (this.tracks || []).find(t => !t.ino)
|
||||
return !this.ino || this._audioFiles.find(abf => !abf.ino) || this._otherFiles.find(f => !f.ino) || this._tracks.find(t => !t.ino)
|
||||
}
|
||||
|
||||
get hasEmbeddedCoverArt() {
|
||||
return !!this._audioFiles.find(af => af.embeddedCoverArt)
|
||||
}
|
||||
|
||||
// TEMP: Issue with inodes not always being set for files
|
||||
getFilesWithMissingIno() {
|
||||
var afs = this._audioFiles.filter(af => !af.ino)
|
||||
var ofs = this._otherFiles.filter(f => !f.ino)
|
||||
var ts = this._tracks.filter(t => !t.ino)
|
||||
return afs.concat(ofs).concat(ts)
|
||||
}
|
||||
|
||||
bookToJSON() {
|
||||
return this.book ? this.book.toJSON() : null
|
||||
}
|
||||
|
@ -332,8 +341,9 @@ class Audiobook {
|
|||
if (this.otherFiles && this.otherFiles.length) {
|
||||
var imageFile = this.otherFiles.find(f => f.filetype === 'image')
|
||||
if (imageFile) {
|
||||
data.coverFullPath = imageFile.fullPath
|
||||
data.cover = Path.normalize(Path.join(`/s/book/${this.id}`, imageFile.path))
|
||||
data.coverFullPath = Path.normalize(imageFile.fullPath)
|
||||
var relImagePath = imageFile.path.replace(this.path, '')
|
||||
data.cover = Path.normalize(Path.join(`/s/book/${this.id}`, relImagePath))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -387,9 +397,9 @@ class Audiobook {
|
|||
}
|
||||
|
||||
// Cover Url may be the same, this ensures the lastUpdate is updated
|
||||
updateBookCover(cover) {
|
||||
updateBookCover(cover, coverFullPath) {
|
||||
if (!this.book) return false
|
||||
return this.book.updateCover(cover)
|
||||
return this.book.updateCover(cover, coverFullPath)
|
||||
}
|
||||
|
||||
updateAudioTracks(orderedFileData) {
|
||||
|
@ -479,7 +489,7 @@ class Audiobook {
|
|||
}
|
||||
|
||||
// If desc.txt is new or forcing rescan then read it and update description (will overwrite)
|
||||
var descriptionTxt = this.otherFiles.find(file => file.filename === 'desc.txt')
|
||||
var descriptionTxt = newOtherFiles.find(file => file.filename === 'desc.txt')
|
||||
if (descriptionTxt && (!alreadyHasDescTxt || forceRescan)) {
|
||||
var newDescription = await readTextFile(descriptionTxt.fullPath)
|
||||
if (newDescription) {
|
||||
|
@ -489,7 +499,7 @@ class Audiobook {
|
|||
}
|
||||
}
|
||||
// If reader.txt is new or forcing rescan then read it and update narrarator (will overwrite)
|
||||
var readerTxt = this.otherFiles.find(file => file.filename === 'reader.txt')
|
||||
var readerTxt = newOtherFiles.find(file => file.filename === 'reader.txt')
|
||||
if (readerTxt && (!alreadyHasReaderTxt || forceRescan)) {
|
||||
var newReader = await readTextFile(readerTxt.fullPath)
|
||||
if (newReader) {
|
||||
|
@ -523,7 +533,7 @@ class Audiobook {
|
|||
var oldFormat = this.book.cover
|
||||
|
||||
// Update book cover path to new format
|
||||
this.book.fullCoverPath = Path.join(this.fullPath, this.book.cover.substr(7))
|
||||
this.book.coverFullPath = Path.normalize(Path.join(this.fullPath, this.book.cover.substr(7)))
|
||||
this.book.cover = Path.normalize(coverStripped.replace(this.path, `/s/book/${this.id}`))
|
||||
Logger.debug(`[Audiobook] updated book cover to new format "${oldFormat}" => "${this.book.cover}"`)
|
||||
}
|
||||
|
@ -531,10 +541,10 @@ class Audiobook {
|
|||
}
|
||||
|
||||
// Check if book was removed from book dir
|
||||
if (this.book.cover && this.book.cover.substr(1).startsWith('s/book/')) {
|
||||
if (this.book.cover && this.book.cover.substr(1).startsWith('s\\book\\')) {
|
||||
// Fixing old cover paths
|
||||
if (!this.book.coverFullPath) {
|
||||
this.book.coverFullPath = Path.join(this.fullPath, this.book.cover.substr(`/s/book/${this.id}`.length))
|
||||
this.book.coverFullPath = Path.normalize(Path.join(this.fullPath, this.book.cover.substr(`/s/book/${this.id}`.length)))
|
||||
Logger.debug(`[Audiobook] Metadata cover full path set "${this.book.coverFullPath}" for "${this.title}"`)
|
||||
hasUpdates = true
|
||||
}
|
||||
|
@ -550,7 +560,7 @@ class Audiobook {
|
|||
if (this.book.cover && this.book.cover.substr(1).startsWith('metadata')) {
|
||||
// Fixing old cover paths
|
||||
if (!this.book.coverFullPath) {
|
||||
this.book.coverFullPath = Path.join(metadataPath, this.book.cover.substr('/metadata/'.length))
|
||||
this.book.coverFullPath = Path.normalize(Path.join(metadataPath, this.book.cover.substr('/metadata/'.length)))
|
||||
Logger.debug(`[Audiobook] Metadata cover full path set "${this.book.coverFullPath}" for "${this.title}"`)
|
||||
hasUpdates = true
|
||||
}
|
||||
|
@ -575,11 +585,12 @@ class Audiobook {
|
|||
// If no cover set and image file exists then use it
|
||||
if (!this.book.cover && imageFiles.length) {
|
||||
var imagePathRelativeToBook = imageFiles[0].path.replace(this.path, '')
|
||||
this.book.cover = Path.join(`/s/book/${this.id}`, imagePathRelativeToBook)
|
||||
this.book.cover = Path.normalize(Path.join(`/s/book/${this.id}`, imagePathRelativeToBook))
|
||||
this.book.coverFullPath = imageFiles[0].fullPath
|
||||
Logger.info(`[Audiobook] Local cover was set to "${this.book.cover}" | "${this.title}"`)
|
||||
hasUpdates = true
|
||||
}
|
||||
|
||||
return hasUpdates
|
||||
}
|
||||
|
||||
|
|
|
@ -20,8 +20,14 @@ class Book {
|
|||
this.cover = null
|
||||
this.coverFullPath = null
|
||||
this.genres = []
|
||||
|
||||
this.lastUpdate = null
|
||||
|
||||
// Should not continue looking up a cover when it is not findable
|
||||
this.lastCoverSearch = null
|
||||
this.lastCoverSearchTitle = null
|
||||
this.lastCoverSearchAuthor = null
|
||||
|
||||
if (book) {
|
||||
this.construct(book)
|
||||
}
|
||||
|
@ -33,6 +39,12 @@ class Book {
|
|||
get _author() { return this.author || '' }
|
||||
get _series() { return this.series || '' }
|
||||
|
||||
get shouldSearchForCover() {
|
||||
if (this.author !== this.lastCoverSearchAuthor || this.title !== this.lastCoverSearchTitle || !this.lastCoverSearch) return true
|
||||
var timeSinceLastSearch = Date.now() - this.lastCoverSearch
|
||||
return timeSinceLastSearch > 1000 * 60 * 60 * 24 * 7 // every 7 days do another lookup
|
||||
}
|
||||
|
||||
construct(book) {
|
||||
this.olid = book.olid
|
||||
this.title = book.title
|
||||
|
@ -50,6 +62,9 @@ class Book {
|
|||
this.coverFullPath = book.coverFullPath || null
|
||||
this.genres = book.genres
|
||||
this.lastUpdate = book.lastUpdate || Date.now()
|
||||
this.lastCoverSearch = book.lastCoverSearch || null
|
||||
this.lastCoverSearchTitle = book.lastCoverSearchTitle || null
|
||||
this.lastCoverSearchAuthor = book.lastCoverSearchAuthor || null
|
||||
}
|
||||
|
||||
toJSON() {
|
||||
|
@ -69,7 +84,10 @@ class Book {
|
|||
cover: this.cover,
|
||||
coverFullPath: this.coverFullPath,
|
||||
genres: this.genres,
|
||||
lastUpdate: this.lastUpdate
|
||||
lastUpdate: this.lastUpdate,
|
||||
lastCoverSearch: this.lastCoverSearch,
|
||||
lastCoverSearchTitle: this.lastCoverSearchTitle,
|
||||
lastCoverSearchAuthor: this.lastCoverSearchAuthor
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -106,6 +124,9 @@ class Book {
|
|||
this.coverFullPath = data.coverFullPath || null
|
||||
this.genres = data.genres || []
|
||||
this.lastUpdate = Date.now()
|
||||
this.lastCoverSearch = data.lastCoverSearch || null
|
||||
this.lastCoverSearchTitle = data.lastCoverSearchTitle || null
|
||||
this.lastCoverSearchAuthor = data.lastCoverSearchAuthor || null
|
||||
|
||||
if (data.author) {
|
||||
this.setParseAuthor(this.author)
|
||||
|
@ -119,6 +140,7 @@ class Book {
|
|||
// If updating to local cover then normalize path
|
||||
if (!payload.cover.startsWith('http:') && !payload.cover.startsWith('https:')) {
|
||||
payload.cover = Path.normalize(payload.cover)
|
||||
if (payload.coverFullPath) payload.coverFullPath = Path.normalize(payload.coverFullPath)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -154,10 +176,19 @@ class Book {
|
|||
return hasUpdates
|
||||
}
|
||||
|
||||
updateCover(cover) {
|
||||
updateLastCoverSearch(coverWasFound) {
|
||||
this.lastCoverSearch = coverWasFound ? null : Date.now()
|
||||
this.lastCoverSearchAuthor = coverWasFound ? null : this.author
|
||||
this.lastCoverSearchTitle = coverWasFound ? null : this.title
|
||||
}
|
||||
|
||||
updateCover(cover, coverFullPath) {
|
||||
if (!cover) return false
|
||||
if (!cover.startsWith('http:') && !cover.startsWith('https:')) {
|
||||
cover = Path.normalize(cover)
|
||||
this.coverFullPath = Path.normalize(coverFullPath)
|
||||
} else {
|
||||
this.coverFullPath = cover
|
||||
}
|
||||
this.cover = cover
|
||||
this.lastUpdate = Date.now()
|
||||
|
|
|
@ -6,6 +6,8 @@ class Library {
|
|||
this.name = null
|
||||
this.folders = []
|
||||
|
||||
this.lastScan = 0
|
||||
|
||||
this.createdAt = null
|
||||
this.lastUpdate = null
|
||||
|
||||
|
@ -74,6 +76,7 @@ class Library {
|
|||
|
||||
if (newFolders.length) {
|
||||
newFolders.forEach((folderData) => {
|
||||
folderData.libraryId = this.id
|
||||
var newFolder = new Folder()
|
||||
newFolder.setData(folderData)
|
||||
this.folders.push(newFolder)
|
||||
|
@ -91,5 +94,9 @@ class Library {
|
|||
checkFullPathInLibrary(fullPath) {
|
||||
return this.folders.find(folder => fullPath.startsWith(folder.fullPath))
|
||||
}
|
||||
|
||||
getFolderById(id) {
|
||||
return this.folders.find(folder => folder.id === id)
|
||||
}
|
||||
}
|
||||
module.exports = Library
|
Loading…
Add table
Add a link
Reference in a new issue