2023-07-04 18:14:44 -05:00
const uuidv4 = require ( "uuid" ) . v4
2021-10-04 22:11:42 -05:00
const Folder = require ( './Folder' )
2022-04-14 17:15:52 -05:00
const LibrarySettings = require ( './settings/LibrarySettings' )
2023-01-05 17:45:27 -06:00
const { filePathToPOSIX } = require ( '../utils/fileUtils' )
2024-02-25 18:32:04 +00:00
/ * *
* @ openapi
* components :
* schemas :
* mediaType :
* type : string
* description : The type of media , will be book or podcast .
* enum : [ book , podcast ]
* oldLibraryId :
* type : string
* description : The ID of the libraries created on server version 2.2 . 23 and before .
* format : "lib_[a-z0-9]{18}"
* example : lib _o78uaoeuh78h6aoeif
* newLibraryId :
* type : string
* description : The library ID for any libraries after 2.3 . 0.
* format : uuid
* example : e4bb1afb - 4 a4f - 4 dd6 - 8 be0 - e615d233185b
2024-02-25 18:42:20 +00:00
* libraryId :
* type : string
* anyOf :
* - $ref : '#/components/schemas/oldLibraryId'
* - $ref : '#/components/schemas/newLibraryId'
2024-02-25 18:32:04 +00:00
* library :
* type : object
* properties :
* id :
2024-02-25 18:42:20 +00:00
* $ref : '#/components/schemas/libraryId'
2024-02-25 18:32:04 +00:00
* name :
* type : string
* description : The name of the library .
* example : Main
* folders :
* type : array
* description : The folders that the library is composed of on the server .
* items :
* $ref : '#/components/schemas/folder'
* displayOrder :
* type : integer
* description : Display position of the library in the list of libraries . Must be >= 1.
* example : 1
* icon :
* type : string
* description : The selected icon for the library . See [ Library Icons ] ( https : //api.audiobookshelf.org/#library-icons) for a list of possible icons.
* example : audiobookshelf
* mediaType :
* - $ref : '#/components/schemas/mediaType'
* provider :
* type : string
* description : Preferred metadata provider for the library . See [ Metadata Providers ] ( https : //api.audiobookshelf.org/#metadata-providers) for a list of possible providers.
* example : audible
* settings :
* $ref : '#/components/schemas/librarySettings'
* createdAt :
* $ref : '#/components/schemas/createdAt'
* lastUpdate :
* type : integer
* description : The time ( in ms since POSIX epoch ) when the library was last updated . ( Read Only )
* example : 1646520916818
* librarySettings :
* type : object
* properties :
* coverAspectRatio :
* type : integer
* description : Whether the library should use square book covers . Must be 0 ( for false ) or 1 ( for true ) .
* example : 1
* disableWatcher :
* type : boolean
* description : Whether to disable the folder watcher for the library .
* example : false
* skipMatchingMediaWithAsin :
* type : boolean
* description : Whether to skip matching books that already have an ASIN .
* example : false
* skipMatchingMediaWithIsbn :
* type : boolean
* description : Whether to skip matching books that already have an ISBN .
* example : false
* autoScanCronExpression :
* description : The cron expression for when to automatically scan the library folders . If null , automatic scanning will be disabled .
* type : [ string , 'null' ]
* libraryFilterData :
* type : object
* properties :
* authors :
* description : The authors of books in the library .
* type : array
* items :
* $ref : '#/components/schemas/authorMinified'
* genres :
* description : The genres of books in the library .
* type : array
* items :
* type : string
* example : Fantasy
* tags :
* $ref : '#/components/schemas/tags'
* series :
* description : The series in the library . The series will only have their id and name .
* type : array
* items :
* type : object
* properties :
* id :
* type : string
* example : ser _cabkj4jeu8be3rap4g
* name :
* type : string
* example : Sword of Truth
* narrators :
* description : The narrators of books in the library .
* type : array
* items :
* type : string
* example : Sam Tsoutsouvas
* languages :
* description : The languages of books in the library .
* type : array
* items :
* type : string
* /
2021-10-04 22:11:42 -05:00
class Library {
constructor ( library = null ) {
this . id = null
2023-07-16 15:05:51 -05:00
this . oldLibraryId = null // TODO: Temp
2021-10-04 22:11:42 -05:00
this . name = null
this . folders = [ ]
2021-10-12 20:07:42 -05:00
this . displayOrder = 1
2022-10-18 12:09:36 -05:00
this . icon = 'database'
2022-03-14 09:56:24 -05:00
this . mediaType = 'book' // book, podcast
2022-02-15 14:59:46 -06:00
this . provider = 'google'
2021-10-04 22:11:42 -05:00
2021-10-05 21:10:49 -05:00
this . lastScan = 0
2023-10-09 17:48:21 -05:00
this . lastScanVersion = null
this . lastScanMetadataPrecedence = null
2022-04-14 17:15:52 -05:00
this . settings = null
2021-10-05 21:10:49 -05:00
2021-10-04 22:11:42 -05:00
this . createdAt = null
this . lastUpdate = null
if ( library ) {
this . construct ( library )
}
}
get folderPaths ( ) {
return this . folders . map ( f => f . fullPath )
}
2022-04-14 18:24:24 -05:00
get isPodcast ( ) {
return this . mediaType === 'podcast'
}
2023-01-02 18:02:04 -06:00
get isMusic ( ) {
return this . mediaType === 'music'
}
2023-06-10 12:46:57 -05:00
get isBook ( ) {
return this . mediaType === 'book'
}
2021-10-04 22:11:42 -05:00
construct ( library ) {
this . id = library . id
2023-07-16 15:05:51 -05:00
this . oldLibraryId = library . oldLibraryId
2021-10-04 22:11:42 -05:00
this . name = library . name
this . folders = ( library . folders || [ ] ) . map ( f => new Folder ( f ) )
2021-10-12 20:07:42 -05:00
this . displayOrder = library . displayOrder || 1
2021-10-09 11:09:06 -05:00
this . icon = library . icon || 'database'
2022-03-14 09:56:24 -05:00
this . mediaType = library . mediaType
2022-02-15 14:59:46 -06:00
this . provider = library . provider || 'google'
2022-04-14 17:15:52 -05:00
this . settings = new LibrarySettings ( library . settings )
if ( library . settings === undefined ) { // LibrarySettings added in v2, migrate settings
this . settings . disableWatcher = ! ! library . disableWatcher
}
2021-10-09 11:09:06 -05:00
2023-10-09 17:48:21 -05:00
this . lastScan = library . lastScan
this . lastScanVersion = library . lastScanVersion
this . lastScanMetadataPrecedence = library . lastScanMetadataPrecedence
2021-10-04 22:11:42 -05:00
this . createdAt = library . createdAt
this . lastUpdate = library . lastUpdate
2022-10-18 12:09:36 -05:00
this . cleanOldValues ( ) // mediaType changed for v2 and icon change for v2.2.2
2022-03-14 09:56:24 -05:00
}
cleanOldValues ( ) {
2022-10-18 12:09:36 -05:00
const availableIcons = [ 'database' , 'audiobookshelf' , 'books-1' , 'books-2' , 'book-1' , 'microphone-1' , 'microphone-3' , 'radio' , 'podcast' , 'rss' , 'headphones' , 'music' , 'file-picture' , 'rocket' , 'power' , 'star' , 'heart' ]
2022-03-18 17:09:17 -05:00
if ( ! availableIcons . includes ( this . icon ) ) {
2022-10-18 12:09:36 -05:00
if ( this . icon === 'audiobook' ) this . icon = 'audiobookshelf'
else if ( this . icon === 'book' ) this . icon = 'books-1'
else if ( this . icon === 'comic' ) this . icon = 'file-picture'
2022-03-18 17:09:17 -05:00
else this . icon = 'database'
2022-03-14 09:56:24 -05:00
}
2022-12-22 16:38:55 -06:00
const mediaTypes = [ 'podcast' , 'book' , 'video' , 'music' ]
if ( ! this . mediaType || ! mediaTypes . includes ( this . mediaType ) ) {
2022-03-18 17:09:17 -05:00
this . mediaType = 'book'
2022-03-14 09:56:24 -05:00
}
2021-10-04 22:11:42 -05:00
}
toJSON ( ) {
return {
id : this . id ,
2023-07-16 15:05:51 -05:00
oldLibraryId : this . oldLibraryId ,
2021-10-04 22:11:42 -05:00
name : this . name ,
folders : ( this . folders || [ ] ) . map ( f => f . toJSON ( ) ) ,
2021-10-12 20:07:42 -05:00
displayOrder : this . displayOrder ,
2021-10-09 11:09:06 -05:00
icon : this . icon ,
2022-03-03 19:03:34 -06:00
mediaType : this . mediaType ,
2022-02-15 14:59:46 -06:00
provider : this . provider ,
2022-04-14 17:15:52 -05:00
settings : this . settings . toJSON ( ) ,
2023-10-09 17:48:21 -05:00
lastScan : this . lastScan ,
lastScanVersion : this . lastScanVersion ,
2021-10-04 22:11:42 -05:00
createdAt : this . createdAt ,
lastUpdate : this . lastUpdate
}
}
setData ( data ) {
2023-07-04 18:14:44 -05:00
this . id = data . id || uuidv4 ( )
2021-10-04 22:11:42 -05:00
this . name = data . name
if ( data . folder ) {
this . folders = [
new Folder ( data . folder )
]
} else if ( data . folders ) {
this . folders = data . folders . map ( folder => {
var newFolder = new Folder ( )
newFolder . setData ( {
fullPath : folder . fullPath ,
libraryId : this . id
} )
return newFolder
} )
}
2021-10-12 20:07:42 -05:00
this . displayOrder = data . displayOrder || 1
2021-10-09 11:09:06 -05:00
this . icon = data . icon || 'database'
2022-03-14 09:56:24 -05:00
this . mediaType = data . mediaType || 'book'
2022-03-19 06:41:54 -05:00
this . provider = data . provider || 'google'
2022-04-14 17:15:52 -05:00
this . settings = new LibrarySettings ( data . settings )
2021-10-04 22:11:42 -05:00
this . createdAt = Date . now ( )
this . lastUpdate = Date . now ( )
}
update ( payload ) {
2023-08-13 17:45:53 -05:00
let hasUpdates = false
2022-03-14 09:56:24 -05:00
2023-08-13 17:45:53 -05:00
const keysToCheck = [ 'name' , 'provider' , 'mediaType' , 'icon' ]
2022-03-14 09:56:24 -05:00
keysToCheck . forEach ( ( key ) => {
if ( payload [ key ] && payload [ key ] !== this [ key ] ) {
this [ key ] = payload [ key ]
hasUpdates = true
}
} )
2022-03-03 19:03:34 -06:00
2022-04-14 17:15:52 -05:00
if ( payload . settings && this . settings . update ( payload . settings ) ) {
2022-02-26 16:34:54 -06:00
hasUpdates = true
}
2022-04-14 17:15:52 -05:00
2021-10-12 20:07:42 -05:00
if ( ! isNaN ( payload . displayOrder ) && payload . displayOrder !== this . displayOrder ) {
this . displayOrder = Number ( payload . displayOrder )
hasUpdates = true
2021-10-04 22:11:42 -05:00
}
if ( payload . folders ) {
2023-08-13 17:45:53 -05:00
const newFolders = payload . folders . filter ( f => ! f . id )
const removedFolders = this . folders . filter ( f => ! payload . folders . some ( _f => _f . id === f . id ) )
2021-10-04 22:11:42 -05:00
if ( removedFolders . length ) {
2023-08-13 17:45:53 -05:00
const removedFolderIds = removedFolders . map ( f => f . id )
2021-10-04 22:11:42 -05:00
this . folders = this . folders . filter ( f => ! removedFolderIds . includes ( f . id ) )
}
if ( newFolders . length ) {
newFolders . forEach ( ( folderData ) => {
2021-10-05 21:10:49 -05:00
folderData . libraryId = this . id
2023-08-13 17:45:53 -05:00
const newFolder = new Folder ( )
2021-10-04 22:11:42 -05:00
newFolder . setData ( folderData )
this . folders . push ( newFolder )
} )
}
2022-02-03 16:39:05 -06:00
if ( newFolders . length || removedFolders . length ) {
hasUpdates = true
}
2021-10-04 22:11:42 -05:00
}
if ( hasUpdates ) {
this . lastUpdate = Date . now ( )
}
return hasUpdates
}
checkFullPathInLibrary ( fullPath ) {
2023-01-05 17:45:27 -06:00
fullPath = filePathToPOSIX ( fullPath )
return this . folders . find ( folder => fullPath . startsWith ( filePathToPOSIX ( folder . fullPath ) ) )
2021-10-04 22:11:42 -05:00
}
2021-10-05 21:10:49 -05:00
getFolderById ( id ) {
return this . folders . find ( folder => folder . id === id )
}
2021-10-04 22:11:42 -05:00
}
module . exports = Library