diff --git a/client/components/app/Appbar.vue b/client/components/app/Appbar.vue
index 21d25832..6ad9553d 100644
--- a/client/components/app/Appbar.vue
+++ b/client/components/app/Appbar.vue
@@ -103,9 +103,6 @@ export default {
userAudiobooks() {
return this.$store.state.user.user.audiobooks || {}
},
- selectedSeries() {
- return this.$store.state.audiobooks.selectedSeries
- },
userCanUpdate() {
return this.$store.getters['user/getUserCanUpdate']
},
diff --git a/client/components/app/BookListRow.vue b/client/components/app/BookListRow.vue
index 192582da..03f90470 100644
--- a/client/components/app/BookListRow.vue
+++ b/client/components/app/BookListRow.vue
@@ -11,7 +11,7 @@
-
+
{{ book.book.title }}: {{ book.book.subtitle }}
@@ -24,7 +24,7 @@
{{ seriesText }}
|
- {{ book.book.publishYear }}
+ {{ book.book.publishedYear }}
|
{{ book.book.description }}
@@ -148,7 +148,7 @@ export default {
this.$store.commit('showEReader', this.book)
},
downloadClick() {
- this.$store.commit('showEditModalOnTab', { audiobook: this.book, tab: 'download' })
+ this.$store.commit('showEditModalOnTab', { libraryItem: this.book, tab: 'download' })
},
toggleRead() {
var updatePayload = {
diff --git a/client/components/app/BookShelfCategorized.vue b/client/components/app/BookShelfCategorized.vue
index 21b04907..ad5efa29 100644
--- a/client/components/app/BookShelfCategorized.vue
+++ b/client/components/app/BookShelfCategorized.vue
@@ -11,7 +11,7 @@
Audiobookshelf is empty!
Configure Scanner
- Scan Audiobooks
+ Scan Library
diff --git a/client/components/app/ConfigSideNav.vue b/client/components/app/ConfigSideNav.vue
index 7443800d..f2574fc2 100644
--- a/client/components/app/ConfigSideNav.vue
+++ b/client/components/app/ConfigSideNav.vue
@@ -9,7 +9,7 @@
-
+
@@ -109,8 +109,8 @@ export default {
githubTagUrl() {
return this.versionData.githubTagUrl
},
- streamAudiobook() {
- return this.$store.state.streamAudiobook
+ streamLibraryItem() {
+ return this.$store.state.streamLibraryItem
}
},
methods: {
diff --git a/client/components/cards/BookMatchCard.vue b/client/components/cards/BookMatchCard.vue
index ca9c83ca..1d35ab3b 100644
--- a/client/components/cards/BookMatchCard.vue
+++ b/client/components/cards/BookMatchCard.vue
@@ -6,7 +6,7 @@
{{ book.title }}
- {{ book.publishYear }}
+ {{ book.publishedYear }}
{{ book.author }}
diff --git a/client/components/cards/LazyBookCard.vue b/client/components/cards/LazyBookCard.vue
index b6f6a8a3..0fc37f57 100644
--- a/client/components/cards/LazyBookCard.vue
+++ b/client/components/cards/LazyBookCard.vue
@@ -149,7 +149,7 @@ export default {
return '/book_placeholder.jpg'
},
bookCoverSrc() {
- return this.store.getters['audiobooks/getLibraryItemCoverSrc'](this._libraryItem, this.placeholderUrl)
+ return this.store.getters['globals/getLibraryItemCoverSrc'](this._libraryItem, this.placeholderUrl)
},
libraryItemId() {
return this._libraryItem.id
@@ -418,7 +418,7 @@ export default {
toast.error(`Failed to mark as ${updatePayload.isRead ? 'Read' : 'Not Read'}`)
})
},
- audiobookScanComplete(result) {
+ itemScanComplete(result) {
this.rescanning = false
var toast = this.$toast || this.$nuxt.$toast
if (!result) {
@@ -433,23 +433,23 @@ export default {
},
rescan() {
this.rescanning = true
- this._socket.once('audiobook_scan_complete', this.audiobookScanComplete)
- this._socket.emit('scan_libraryItem', this.libraryItemId)
+ this._socket.once('item_scan_complete', this.itemScanComplete)
+ this._socket.emit('scan_item', this.libraryItemId)
},
showEditModalTracks() {
// More menu func
- this.store.commit('showEditModalOnTab', { audiobook: this.audiobook, tab: 'tracks' })
+ this.store.commit('showEditModalOnTab', { libraryItem: this.audiobook, tab: 'tracks' })
},
showEditModalMatch() {
// More menu func
- this.store.commit('showEditModalOnTab', { audiobook: this.audiobook, tab: 'match' })
+ this.store.commit('showEditModalOnTab', { libraryItem: this.audiobook, tab: 'match' })
},
showEditModalDownload() {
// More menu func
- this.store.commit('showEditModalOnTab', { audiobook: this.audiobook, tab: 'download' })
+ this.store.commit('showEditModalOnTab', { libraryItem: this.audiobook, tab: 'download' })
},
openCollections() {
- this.store.commit('setSelectedAudiobook', this.audiobook)
+ this.store.commit('setSelectedLibraryItem', this.audiobook)
this.store.commit('globals/setShowUserCollectionsModal', true)
},
createMoreMenu() {
diff --git a/client/components/covers/BookCover.vue b/client/components/covers/BookCover.vue
index b5efade4..38449b3c 100644
--- a/client/components/covers/BookCover.vue
+++ b/client/components/covers/BookCover.vue
@@ -99,7 +99,7 @@ export default {
fullCoverUrl() {
if (!this.libraryItem) return null
var store = this.$store || this.$nuxt.$store
- return store.getters['audiobooks/getLibraryItemCoverSrc'](this.libraryItem, this.placeholderUrl)
+ return store.getters['globals/getLibraryItemCoverSrc'](this.libraryItem, this.placeholderUrl)
},
cover() {
return this.media.coverPath || this.placeholderUrl
diff --git a/client/components/covers/GroupCover.vue b/client/components/covers/GroupCover.vue
index 88c31501..8af50fd0 100644
--- a/client/components/covers/GroupCover.vue
+++ b/client/components/covers/GroupCover.vue
@@ -63,7 +63,7 @@ export default {
},
methods: {
getCoverUrl(book) {
- return this.store.getters['audiobooks/getLibraryItemCoverSrc'](book, '')
+ return this.store.getters['globals/getLibraryItemCoverSrc'](book, '')
},
async buildCoverImg(coverData, bgCoverWidth, offsetLeft, zIndex, forceCoverBg = false) {
var src = coverData.coverUrl
diff --git a/client/components/covers/HoverBookCover.vue b/client/components/covers/HoverBookCover.vue
index 1bed83db..7171061e 100644
--- a/client/components/covers/HoverBookCover.vue
+++ b/client/components/covers/HoverBookCover.vue
@@ -22,7 +22,7 @@ export default {
return '/book_placeholder.jpg'
},
fullCoverUrl() {
- return this.$store.getters['audiobooks/getLibraryItemCoverSrc'](this.audiobook, this.placeholderUrl)
+ return this.$store.getters['globals/getLibraryItemCoverSrc'](this.audiobook, this.placeholderUrl)
},
hasCover() {
return !!this.audiobook.book.cover
diff --git a/client/components/modals/EditModal.vue b/client/components/modals/EditModal.vue
index 61fa48f5..f6b06ce8 100644
--- a/client/components/modals/EditModal.vue
+++ b/client/components/modals/EditModal.vue
@@ -169,7 +169,7 @@ export default {
if (this.currentBookshelfIndex - 1 < 0) return
var prevBookId = this.bookshelfBookIds[this.currentBookshelfIndex - 1]
this.processing = true
- var prevBook = await this.$axios.$get(`/api/books/${prevBookId}`).catch((error) => {
+ var prevBook = await this.$axios.$get(`/api/items/${prevBookId}`).catch((error) => {
var errorMsg = error.response && error.response.data ? error.response.data : 'Failed to fetch book'
this.$toast.error(errorMsg)
return null
@@ -186,7 +186,7 @@ export default {
if (this.currentBookshelfIndex >= this.bookshelfBookIds.length - 1) return
this.processing = true
var nextBookId = this.bookshelfBookIds[this.currentBookshelfIndex + 1]
- var nextBook = await this.$axios.$get(`/api/books/${nextBookId}`).catch((error) => {
+ var nextBook = await this.$axios.$get(`/api/items/${nextBookId}`).catch((error) => {
var errorMsg = error.response && error.response.data ? error.response.data : 'Failed to fetch book'
this.$toast.error(errorMsg)
return null
diff --git a/client/components/modals/UserCollectionsModal.vue b/client/components/modals/UserCollectionsModal.vue
index 9cbedf98..2160a64d 100644
--- a/client/components/modals/UserCollectionsModal.vue
+++ b/client/components/modals/UserCollectionsModal.vue
@@ -15,7 +15,7 @@
-
+
@@ -50,7 +50,7 @@ export default {
this.loadCollections()
this.newCollectionName = ''
} else {
- this.$store.commit('setSelectedAudiobook', null)
+ this.$store.commit('setSelectedLibraryItem', null)
}
}
},
@@ -65,15 +65,18 @@ export default {
},
title() {
if (this.showBatchUserCollectionModal) {
- return `${this.selectedBookIds.length} Books Selected`
+ return `${this.selectedBookIds.length} Items Selected`
}
- return this.selectedAudiobook ? this.selectedAudiobook.book.title : ''
+ return this.selectedLibraryItem ? this.selectedLibraryItem.media.metadata.title : ''
},
- selectedAudiobook() {
- return this.$store.state.selectedAudiobook
+ bookCoverAspectRatio() {
+ return this.$store.getters['getBookCoverAspectRatio']
},
- selectedAudiobookId() {
- return this.selectedAudiobook ? this.selectedAudiobook.id : null
+ selectedLibraryItem() {
+ return this.$store.state.selectedLibraryItem
+ },
+ selectedLibraryItemId() {
+ return this.selectedLibraryItem ? this.selectedLibraryItem.id : null
},
collections() {
return this.$store.state.user.collections || []
@@ -87,7 +90,7 @@ export default {
var collectionBookIds = c.books.map((b) => b.id)
includesBook = !this.selectedBookIds.find((id) => !collectionBookIds.includes(id))
} else {
- includesBook = !!c.books.find((b) => b.id === this.selectedAudiobookId)
+ includesBook = !!c.books.find((b) => b.id === this.selectedLibraryItemId)
}
return {
@@ -112,7 +115,7 @@ export default {
this.$store.dispatch('user/loadUserCollections')
},
removeFromCollection(collection) {
- if (!this.selectedAudiobookId && !this.selectedBookIds.length) return
+ if (!this.selectedLibraryItemId && !this.selectedBookIds.length) return
this.processing = true
if (this.showBatchUserCollectionModal) {
@@ -132,7 +135,7 @@ export default {
} else {
// Remove single book
this.$axios
- .$delete(`/api/collections/${collection.id}/book/${this.selectedAudiobookId}`)
+ .$delete(`/api/collections/${collection.id}/book/${this.selectedLibraryItemId}`)
.then((updatedCollection) => {
console.log(`Book removed from collection`, updatedCollection)
this.$toast.success('Book removed from collection')
@@ -146,7 +149,7 @@ export default {
}
},
addToCollection(collection) {
- if (!this.selectedAudiobookId && !this.selectedBookIds.length) return
+ if (!this.selectedLibraryItemId && !this.selectedBookIds.length) return
this.processing = true
if (this.showBatchUserCollectionModal) {
@@ -164,10 +167,10 @@ export default {
this.processing = false
})
} else {
- if (!this.selectedAudiobookId) return
+ if (!this.selectedLibraryItemId) return
this.$axios
- .$post(`/api/collections/${collection.id}/book`, { id: this.selectedAudiobookId })
+ .$post(`/api/collections/${collection.id}/book`, { id: this.selectedLibraryItemId })
.then((updatedCollection) => {
console.log(`Book added to collection`, updatedCollection)
this.$toast.success('Book added to collection')
@@ -181,12 +184,12 @@ export default {
}
},
submitCreateCollection() {
- if (!this.newCollectionName || (!this.selectedAudiobookId && !this.selectedBookIds.length)) {
+ if (!this.newCollectionName || (!this.selectedLibraryItemId && !this.selectedBookIds.length)) {
return
}
this.processing = true
- var books = this.showBatchUserCollectionModal ? this.selectedBookIds : [this.selectedAudiobookId]
+ var books = this.showBatchUserCollectionModal ? this.selectedBookIds : [this.selectedLibraryItemId]
var newCollection = {
books: books,
libraryId: this.currentLibraryId,
diff --git a/client/components/modals/collections/UserCollectionItem.vue b/client/components/modals/collections/UserCollectionItem.vue
index d7655484..c79efda7 100644
--- a/client/components/modals/collections/UserCollectionItem.vue
+++ b/client/components/modals/collections/UserCollectionItem.vue
@@ -4,7 +4,7 @@
-
+
Full Path
-
+
Manage Tracks
diff --git a/client/components/tables/UsersTable.vue b/client/components/tables/UsersTable.vue
index f1ed44c2..89b3232e 100644
--- a/client/components/tables/UsersTable.vue
+++ b/client/components/tables/UsersTable.vue
@@ -76,9 +76,6 @@ export default {
currentUserId() {
return this.$store.state.user.user.id
},
- userStream() {
- return this.$store.state.streamAudiobook
- },
usersOnline() {
var usermap = {}
this.$store.state.users.users.forEach((u) => (usermap[u.id] = { online: true, stream: u.stream }))
diff --git a/client/components/widgets/ItemDetailsEdit.vue b/client/components/widgets/ItemDetailsEdit.vue
index aa529972..959a7012 100644
--- a/client/components/widgets/ItemDetailsEdit.vue
+++ b/client/components/widgets/ItemDetailsEdit.vue
@@ -17,7 +17,7 @@
-
+
@@ -108,7 +108,7 @@ export default {
authors: [],
narrators: [],
series: [],
- publishYear: null,
+ publishedYear: null,
publisher: null,
language: null,
isbn: null,
@@ -173,6 +173,13 @@ export default {
this.forceBlur()
return this.checkForChanges()
},
+ getTitleAndAuthorName() {
+ this.forceBlur()
+ return {
+ title: this.details.title,
+ author: (this.details.authors || []).map((au) => au.name).join(', ')
+ }
+ },
mapBatchDetails(batchDetails) {
for (const key in batchDetails) {
if (key === 'tags') {
@@ -317,7 +324,7 @@ export default {
this.details.narrators = [...(this.mediaMetadata.narrators || [])]
this.details.genres = [...(this.mediaMetadata.genres || [])]
this.details.series = (this.mediaMetadata.series || []).map((se) => ({ ...se }))
- this.details.publishYear = this.mediaMetadata.publishYear
+ this.details.publishedYear = this.mediaMetadata.publishedYear
this.details.publisher = this.mediaMetadata.publisher || null
this.details.language = this.mediaMetadata.language || null
this.details.isbn = this.mediaMetadata.isbn || null
diff --git a/client/layouts/default.vue b/client/layouts/default.vue
index 123e5f0e..24355601 100644
--- a/client/layouts/default.vue
+++ b/client/layouts/default.vue
@@ -35,9 +35,6 @@ export default {
if (this.$store.state.selectedLibraryItems) {
this.$store.commit('setSelectedLibraryItems', [])
}
- if (this.$store.state.audiobooks.keywordFilter) {
- this.$store.commit('audiobooks/setKeywordFilter', '')
- }
}
},
computed: {
@@ -282,12 +279,6 @@ export default {
if (!download || !download.audiobookId) {
return console.error('Invalid download object', download)
}
-
- // var audiobook = this.$store.getters['audiobooks/getAudiobook'](download.audiobookId)
- // if (!audiobook) {
- // return console.error('Audiobook not found for download', download)
- // }
- // this.$store.commit('showEditModalOnTab', { audiobook, tab: 'download' })
},
downloadStarted(download) {
download.status = this.$constants.DownloadStatus.PENDING
@@ -495,7 +486,7 @@ export default {
}
// Playing audiobook
- if (this.$store.state.streamAudiobook && Object.values(this.$hotkeys.AudioPlayer).includes(name)) {
+ if (this.$store.state.streamLibraryItem && Object.values(this.$hotkeys.AudioPlayer).includes(name)) {
this.$eventBus.$emit('player-hotkey', name)
e.preventDefault()
}
diff --git a/client/pages/account.vue b/client/pages/account.vue
index d6640242..4ce7d1bb 100644
--- a/client/pages/account.vue
+++ b/client/pages/account.vue
@@ -1,5 +1,5 @@
-
+
Account
@@ -46,8 +46,8 @@ export default {
}
},
computed: {
- streamAudiobook() {
- return this.$store.state.streamAudiobook
+ streamLibraryItem() {
+ return this.$store.state.streamLibraryItem
},
user() {
return this.$store.state.user.user || null
diff --git a/client/pages/audiobook/_id/edit.vue b/client/pages/audiobook/_id/edit.vue
deleted file mode 100644
index 4542f171..00000000
--- a/client/pages/audiobook/_id/edit.vue
+++ /dev/null
@@ -1,280 +0,0 @@
-
-
-
-
-
-
-
- Drag files into correct track order
- Save Tracklist
-
-
- New
-
- Current
- {{ currentSort === 'current' ? 'expand_more' : 'unfold_more' }}
-
-
- Track From Filename
- {{ currentSort === 'track-filename' ? 'expand_more' : 'unfold_more' }}
-
-
- Track From Metadata
- {{ currentSort === 'metadata' ? 'expand_more' : 'unfold_more' }}
-
- Disc From Filename
- Disc From Metadata
-
- Filename
- {{ currentSort === 'filename' ? 'expand_more' : 'unfold_more' }}
-
-
-
- Size
- Duration
- Status
- Notes
- Include in Tracklist
-
-
-
-
-
- {{ audio.include ? index - numExcluded + 1 : -1 }}
-
- {{ audio.index }}
-
- {{ audio.trackNumFromFilename }}
-
-
- {{ audio.trackNumFromMeta }}
-
-
- {{ audio.discNumFromFilename }}
-
-
- {{ audio.discNumFromMeta }}
-
-
- {{ audio.filename }}
-
-
-
- {{ $bytesPretty(audio.size) }}
-
-
- {{ $secondsToTimestamp(audio.duration) }}
-
-
- {{ getStatusIcon(audio) }}
-
-
- {{ audio.error }}
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/client/pages/audiobook/_id/index.vue b/client/pages/audiobook/_id/index.vue
deleted file mode 100644
index 62f3503a..00000000
--- a/client/pages/audiobook/_id/index.vue
+++ /dev/null
@@ -1,494 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- play_circle_filled
-
-
-
- edit
-
-
-
-
-
-
-
-
- {{ title }}
-
- {{ subtitle }}
-
-
-
-
- by {{ author }},
-
- by Unknown
- {{ seriesText }}
-
-
-
- Narrated By
-
-
-
- {{ narrator }},
-
-
-
-
-
- Publish Year
-
-
- {{ publishYear }}
-
-
-
-
- Genres
-
-
-
- {{ genre }},
-
-
-
-
-
- Duration
-
-
- {{ durationPretty }}
-
-
-
-
- Size
-
-
- {{ sizePretty }}
-
-
-
-
-
-
-
-
- warning_amber
- Book has no audio tracks but has valid ebook files. The e-reader is experimental and can be turned on in config.
-
-
-
-
- Your Progress: {{ Math.round(progressPercent * 100) }}%
- Finished {{ $formatDate(userProgressFinishedAt, 'MM/dd/yyyy') }}
- {{ $elapsedPretty(userTimeRemaining) }} remaining
- Started {{ $formatDate(userProgressStartedAt, 'MM/dd/yyyy') }}
-
-
- close
-
-
-
-
-
- play_arrow
- {{ streaming ? 'Streaming' : 'Play' }}
-
-
- error
- {{ isMissing ? 'Missing' : 'Incomplete' }}
-
-
-
- auto_stories
- Read
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Open RSS Feed
-
-
-
-
-
-
- Missing Parts ({{ missingParts.length }})
-
- {{ missingPartChunks.join(', ') }}
-
-
-
-
- Invalid Parts ({{ invalidParts.length }})
-
-
- {{ part.filename }}: {{ part.error }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/client/pages/batch/index.vue b/client/pages/batch/index.vue
index 45f3e616..50c5381e 100644
--- a/client/pages/batch/index.vue
+++ b/client/pages/batch/index.vue
@@ -19,8 +19,8 @@
-
-
+
+
@@ -114,7 +114,7 @@ export default {
batchDetails: {
subtitle: null,
authors: null,
- publishYear: null,
+ publishedYear: null,
series: [],
genres: [],
tags: [],
@@ -126,7 +126,7 @@ export default {
selectedBatchUsage: {
subtitle: false,
authors: false,
- publishYear: false,
+ publishedYear: false,
series: false,
genres: false,
tags: false,
diff --git a/client/pages/collection/_id.vue b/client/pages/collection/_id.vue
index 92d5dab5..7a1ba261 100644
--- a/client/pages/collection/_id.vue
+++ b/client/pages/collection/_id.vue
@@ -1,5 +1,5 @@
-
+
@@ -66,8 +66,8 @@ export default {
bookCoverAspectRatio() {
return this.$store.getters['getBookCoverAspectRatio']
},
- streamAudiobook() {
- return this.$store.state.streamAudiobook
+ streamLibraryItem() {
+ return this.$store.state.streamLibraryItem
},
bookItems() {
return this.collection.books || []
diff --git a/client/pages/config.vue b/client/pages/config.vue
index a033cc02..efd162b0 100644
--- a/client/pages/config.vue
+++ b/client/pages/config.vue
@@ -1,5 +1,5 @@
-
+
@@ -38,8 +38,8 @@ export default {
isMobile() {
return this.$store.state.globals.isMobile
},
- streamAudiobook() {
- return this.$store.state.streamAudiobook
+ streamLibraryItem() {
+ return this.$store.state.streamLibraryItem
},
currentPage() {
if (!this.$route.name) return 'Settings'
diff --git a/client/pages/config/index.vue b/client/pages/config/index.vue
index d4d099fb..5e2d8d3e 100644
--- a/client/pages/config/index.vue
+++ b/client/pages/config/index.vue
@@ -120,7 +120,7 @@
Purge Cache
- Remove All Audiobooks
+ Remove All Library Items
Report bugs, request features, and contribute on
@@ -169,9 +169,6 @@
-
@@ -181,14 +178,14 @@
export default {
data() {
return {
- isResettingAudiobooks: false,
+ isResettingLibraryItems: false,
updatingServerSettings: false,
useSquareBookCovers: false,
useAlternativeBookshelfView: false,
isPurgingCache: false,
newServerSettings: {},
tooltips: {
- scannerDisableWatcher: 'Disables the automatic adding/updating of audiobooks when file changes are detected. *Requires server restart',
+ scannerDisableWatcher: 'Disables the automatic adding/updating of items when file changes are detected. *Requires server restart',
scannerPreferOpfMetadata: 'OPF file metadata will be used for book details over folder names',
scannerPreferAudioMetadata: 'Audio file ID3 meta tags will be used for book details over folder names',
scannerParseSubtitle: 'Extract subtitles from audiobook folder names. Subtitle must be seperated by " - " i.e. "Book Title - A Subtitle Here" has the subtitle "A Subtitle Here"',
@@ -271,20 +268,20 @@ export default {
this.useAlternativeBookshelfView = this.newServerSettings.bookshelfView === this.$constants.BookshelfView.TITLES
},
- resetAudiobooks() {
- if (confirm('WARNING! This action will remove all audiobooks from the database including any updates or matches you have made. This does not do anything to your actual files. Shall we continue?')) {
- this.isResettingAudiobooks = true
+ resetLibraryItems() {
+ if (confirm('WARNING! This action will remove all library items from the database including any updates or matches you have made. This does not do anything to your actual files. Shall we continue?')) {
+ this.isResettingLibraryItems = true
this.$axios
- .$delete('/api/books/all')
+ .$delete('/api/items/all')
.then(() => {
- this.isResettingAudiobooks = false
- this.$toast.success('Successfully reset audiobooks')
+ this.isResettingLibraryItems = false
+ this.$toast.success('Successfully reset items')
location.reload()
})
.catch((error) => {
- console.error('failed to reset audiobooks', error)
- this.isResettingAudiobooks = false
- this.$toast.error('Failed to reset audiobooks - manually remove the /config/audiobooks folder')
+ console.error('failed to reset items', error)
+ this.isResettingLibraryItems = false
+ this.$toast.error('Failed to reset items - manually remove the /config/libraryItems folder')
})
}
},
diff --git a/client/pages/config/log.vue b/client/pages/config/log.vue
index 57b05f9b..42c7e6fc 100644
--- a/client/pages/config/log.vue
+++ b/client/pages/config/log.vue
@@ -1,5 +1,5 @@
-
+
Logger
@@ -93,8 +93,8 @@ export default {
serverSettings() {
return this.$store.state.serverSettings
},
- streamAudiobook() {
- return this.$store.state.streamAudiobook
+ streamLibraryItem() {
+ return this.$store.state.streamLibraryItem
}
},
methods: {
diff --git a/client/pages/index.vue b/client/pages/index.vue
index e7d21eaa..2d00f4cb 100644
--- a/client/pages/index.vue
+++ b/client/pages/index.vue
@@ -1,5 +1,5 @@
-
+
diff --git a/client/pages/library/_library/authors/index.vue b/client/pages/library/_library/authors/index.vue
index 8fcb7366..9a35af81 100644
--- a/client/pages/library/_library/authors/index.vue
+++ b/client/pages/library/_library/authors/index.vue
@@ -1,5 +1,5 @@
-
+
@@ -38,8 +38,8 @@ export default {
}
},
computed: {
- streamAudiobook() {
- return this.$store.state.streamAudiobook
+ streamLibraryItem() {
+ return this.$store.state.streamLibraryItem
},
currentLibraryId() {
return this.$store.state.libraries.currentLibraryId
diff --git a/client/pages/library/_library/bookshelf/_id.vue b/client/pages/library/_library/bookshelf/_id.vue
index 78b183b4..30f8b551 100644
--- a/client/pages/library/_library/bookshelf/_id.vue
+++ b/client/pages/library/_library/bookshelf/_id.vue
@@ -1,5 +1,5 @@
-
+
@@ -34,8 +34,8 @@ export default {
}
},
computed: {
- streamAudiobook() {
- return this.$store.state.streamAudiobook
+ streamLibraryItem() {
+ return this.$store.state.streamLibraryItem
}
},
methods: {}
diff --git a/client/pages/library/_library/index.vue b/client/pages/library/_library/index.vue
index decd934c..a350d30e 100644
--- a/client/pages/library/_library/index.vue
+++ b/client/pages/library/_library/index.vue
@@ -1,5 +1,5 @@
-
+
@@ -26,8 +26,8 @@ export default {
return {}
},
computed: {
- streamAudiobook() {
- return this.$store.state.streamAudiobook
+ streamLibraryItem() {
+ return this.$store.state.streamLibraryItem
}
},
methods: {},
diff --git a/client/pages/library/_library/podcast/search.vue b/client/pages/library/_library/podcast/search.vue
index 3b35a50a..e323864f 100644
--- a/client/pages/library/_library/podcast/search.vue
+++ b/client/pages/library/_library/podcast/search.vue
@@ -1,5 +1,5 @@
-
+
@@ -49,8 +49,8 @@ export default {
}
},
computed: {
- streamAudiobook() {
- return this.$store.state.streamAudiobook
+ streamLibraryItem() {
+ return this.$store.state.streamLibraryItem
}
},
methods: {
diff --git a/client/pages/library/_library/search.vue b/client/pages/library/_library/search.vue
index b34f7cce..dd3b3153 100644
--- a/client/pages/library/_library/search.vue
+++ b/client/pages/library/_library/search.vue
@@ -1,5 +1,5 @@
-
+
@@ -53,8 +53,8 @@ export default {
}
},
computed: {
- streamAudiobook() {
- return this.$store.state.streamAudiobook
+ streamLibraryItem() {
+ return this.$store.state.streamLibraryItem
},
hasResults() {
return Object.values(this.results).find((r) => !!r)
diff --git a/client/pages/library/_library/series/_id.vue b/client/pages/library/_library/series/_id.vue
index dce9ec01..054f19cf 100644
--- a/client/pages/library/_library/series/_id.vue
+++ b/client/pages/library/_library/series/_id.vue
@@ -1,5 +1,5 @@
-
+
@@ -35,8 +35,8 @@ export default {
return {}
},
computed: {
- streamAudiobook() {
- return this.$store.state.streamAudiobook
+ streamLibraryItem() {
+ return this.$store.state.streamLibraryItem
}
},
mounted() {},
diff --git a/client/pages/upload/index.vue b/client/pages/upload/index.vue
index c97ef200..53303231 100644
--- a/client/pages/upload/index.vue
+++ b/client/pages/upload/index.vue
@@ -1,5 +1,5 @@
-
+
@@ -91,8 +91,8 @@ export default {
})
return extensions
},
- streamAudiobook() {
- return this.$store.state.streamAudiobook
+ streamLibraryItem() {
+ return this.$store.state.streamLibraryItem
},
libraries() {
return this.$store.state.libraries.libraries
diff --git a/client/players/CastPlayer.js b/client/players/CastPlayer.js
index 1d841f5e..7e7da44a 100644
--- a/client/players/CastPlayer.js
+++ b/client/players/CastPlayer.js
@@ -76,7 +76,7 @@ export default class CastPlayer extends EventEmitter {
this.currentTime = startTime
- var coverImg = this.ctx.$store.getters['audiobooks/getLibraryItemCoverSrc'](audiobook)
+ var coverImg = this.ctx.$store.getters['globals/getLibraryItemCoverSrc'](audiobook)
if (process.env.NODE_ENV === 'development') {
this.coverUrl = coverImg
} else {
diff --git a/client/plugins/chromecast.js b/client/plugins/chromecast.js
index 00cf3e3f..5eac0ecd 100644
--- a/client/plugins/chromecast.js
+++ b/client/plugins/chromecast.js
@@ -1,9 +1,9 @@
export default (ctx) => {
var sendInit = async (castContext) => {
// Fetch background covers for chromecast (temp)
- var covers = await ctx.$axios.$get(`/api/libraries/${ctx.$store.state.libraries.currentLibraryId}/books/all?limit=40&minified=1`).then((data) => {
+ var covers = await ctx.$axios.$get(`/api/libraries/${ctx.$store.state.libraries.currentLibraryId}/items?limit=40&minified=1`).then((data) => {
return data.results.filter((b) => b.book.cover).map((ab) => {
- var coverUrl = ctx.$store.getters['audiobooks/getLibraryItemCoverSrc'](ab)
+ var coverUrl = ctx.$store.getters['globals/getLibraryItemCoverSrc'](ab)
if (process.env.NODE_ENV === 'development') return coverUrl
return `${window.location.origin}${coverUrl}`
})
diff --git a/client/store/audiobooks.js b/client/store/audiobooks.js
deleted file mode 100644
index 6e8a3fef..00000000
--- a/client/store/audiobooks.js
+++ /dev/null
@@ -1,135 +0,0 @@
-const STANDARD_GENRES = ['Adventure', 'Autobiography', 'Biography', 'Childrens', 'Comedy', 'Crime', 'Dystopian', 'Fantasy', 'Fiction', 'Health', 'History', 'Horror', 'Mystery', 'New Adult', 'Nonfiction', 'Philosophy', 'Politics', 'Religion', 'Romance', 'Sci-Fi', 'Self-Help', 'Short Story', 'Technology', 'Thriller', 'True Crime', 'Western', 'Young Adult']
-
-export const state = () => ({
- audiobooks: [],
- loadedLibraryId: '',
- listeners: [],
- genres: [...STANDARD_GENRES],
- tags: [],
- series: [],
- keywordFilter: null,
- selectedSeries: null
-})
-
-export const getters = {
- getLibraryItemCoverSrc: (state, getters, rootState, rootGetters) => (libraryItem, placeholder = '/book_placeholder.jpg') => {
- if (!libraryItem) return placeholder
- var media = libraryItem.media
- if (!media || !media.coverPath || media.coverPath === placeholder) return placeholder
-
- // Absolute URL covers (should no longer be used)
- if (media.coverPath.startsWith('http:') || media.coverPath.startsWith('https:')) return media.coverPath
-
- var userToken = rootGetters['user/getToken']
- var lastUpdate = libraryItem.updatedAt || Date.now()
-
- if (process.env.NODE_ENV !== 'production') { // Testing
- return `http://localhost:3333/api/items/${libraryItem.id}/cover?token=${userToken}&ts=${lastUpdate}`
- }
- return `/api/items/${libraryItem.id}/cover?token=${userToken}&ts=${lastUpdate}`
- }
-}
-
-export const actions = {
-
-}
-
-export const mutations = {
- setKeywordFilter(state, val) {
- state.keywordFilter = val
- },
- setSelectedSeries(state, val) {
- state.selectedSeries = val
- },
- set(state, audiobooks) {
- // GENRES
- var genres = [...state.genres]
- audiobooks.forEach((ab) => {
- if (!ab.book) return
- genres = genres.concat(ab.book.genres)
- })
- state.genres = [...new Set(genres)] // Remove Duplicates
- state.genres.sort((a, b) => a.toLowerCase() < b.toLowerCase() ? -1 : 1)
-
- // TAGS
- var tags = []
- audiobooks.forEach((ab) => {
- tags = tags.concat(ab.tags)
- })
- state.tags = [...new Set(tags)] // Remove Duplicates
- state.tags.sort((a, b) => a.toLowerCase() < b.toLowerCase() ? -1 : 1)
-
- // SERIES
- var series = []
- audiobooks.forEach((ab) => {
- if (!ab.book || !ab.book.series || series.includes(ab.book.series)) return
- series.push(ab.book.series)
- })
- state.series = series
- state.series.sort((a, b) => a.toLowerCase() < b.toLowerCase() ? -1 : 1)
-
- state.audiobooks = audiobooks
- state.listeners.forEach((listener) => {
- listener.meth()
- })
- },
- remove(state, audiobook) {
- state.audiobooks = state.audiobooks.filter(a => a.id !== audiobook.id)
-
- if (audiobook.book) {
- // GENRES
- audiobook.book.genres.forEach((genre) => {
- if (!STANDARD_GENRES.includes(genre)) {
- var isInOtherAB = state.audiobooks.find(ab => {
- return ab.book && ab.book.genres.includes(genre)
- })
- if (!isInOtherAB) {
- // Genre is not used by any other audiobook - remove it
- state.genres = state.genres.filter(g => g !== genre)
- }
- }
- })
-
- // SERIES
- if (audiobook.book.series) {
- var isInOtherAB = state.audiobooks.find(ab => ab.book && ab.book.series === audiobook.book.series)
- if (!isInOtherAB) {
- // Series not used in any other audiobook - remove it
- state.series = state.series.filter(s => s !== audiobook.book.series)
- }
- }
- }
-
- // TAGS
- audiobook.tags.forEach((tag) => {
- var isInOtherAB = state.audiobooks.find(ab => {
- return ab.tags.includes(tag)
- })
- if (!isInOtherAB) {
- // Tag is not used by any other audiobook - remove it
- state.tags = state.tags.filter(t => t !== tag)
- }
- })
-
- state.listeners.forEach((listener) => {
- if (!listener.audiobookId || listener.audiobookId === audiobook.id) {
- listener.meth()
- }
- })
- },
- addListener(state, listener) {
- var index = state.listeners.findIndex(l => l.id === listener.id)
- if (index >= 0) state.listeners.splice(index, 1, listener)
- else state.listeners.push(listener)
- },
- removeListener(state, listenerId) {
- state.listeners = state.listeners.filter(l => l.id !== listenerId)
- },
- audiobookUpdated(state, audiobook) {
- state.listeners.forEach((listener) => {
- if (!listener.audiobookId || listener.audiobookId === audiobook.id) {
- listener.meth()
- }
- })
- }
-}
\ No newline at end of file
diff --git a/client/store/globals.js b/client/store/globals.js
index 2720c760..07412af4 100644
--- a/client/store/globals.js
+++ b/client/store/globals.js
@@ -11,7 +11,24 @@ export const state = () => ({
isChromecastInitialized: false // Script loaded
})
-export const getters = {}
+export const getters = {
+ getLibraryItemCoverSrc: (state, getters, rootState, rootGetters) => (libraryItem, placeholder = '/book_placeholder.jpg') => {
+ if (!libraryItem) return placeholder
+ var media = libraryItem.media
+ if (!media || !media.coverPath || media.coverPath === placeholder) return placeholder
+
+ // Absolute URL covers (should no longer be used)
+ if (media.coverPath.startsWith('http:') || media.coverPath.startsWith('https:')) return media.coverPath
+
+ var userToken = rootGetters['user/getToken']
+ var lastUpdate = libraryItem.updatedAt || Date.now()
+
+ if (process.env.NODE_ENV !== 'production') { // Testing
+ return `http://localhost:3333/api/items/${libraryItem.id}/cover?token=${userToken}&ts=${lastUpdate}`
+ }
+ return `/api/items/${libraryItem.id}/cover?token=${userToken}&ts=${lastUpdate}`
+ }
+}
export const mutations = {
updateWindowSize(state, { width, height }) {
diff --git a/client/store/index.js b/client/store/index.js
index cf6745e1..7a3fcfd7 100644
--- a/client/store/index.js
+++ b/client/store/index.js
@@ -8,7 +8,6 @@ export const state = () => ({
editModalTab: 'details',
showEditModal: false,
showEReader: false,
- selectedAudiobook: null,
selectedLibraryItem: null,
selectedAudiobookFile: null,
developerMode: false,
diff --git a/client/store/libraries.js b/client/store/libraries.js
index d7fee8a7..7b02045f 100644
--- a/client/store/libraries.js
+++ b/client/store/libraries.js
@@ -68,11 +68,6 @@ export const actions = {
console.warn('Access not allowed to library')
return false
}
- // var library = state.libraries.find(lib => lib.id === libraryId)
- // if (library) {
- // commit('setCurrentLibrary', libraryId)
- // return library
- // }
return this.$axios
.$get(`/api/libraries/${libraryId}?include=filterdata`)
diff --git a/server/ApiController.js b/server/ApiController.js
index a6b109cd..a050bb69 100644
--- a/server/ApiController.js
+++ b/server/ApiController.js
@@ -8,7 +8,6 @@ const Logger = require('./Logger')
const { isObject } = require('./utils/index')
const { parsePodcastRssFeedXml } = require('./utils/podcastUtils')
-const BookController = require('./controllers/BookController')
const LibraryController = require('./controllers/LibraryController')
const UserController = require('./controllers/UserController')
const CollectionController = require('./controllers/CollectionController')
@@ -74,6 +73,8 @@ class ApiController {
//
// Item Routes
//
+ this.router.delete('/items/all', LibraryItemController.deleteAll.bind(this))
+
this.router.get('/items/:id', LibraryItemController.middleware.bind(this), LibraryItemController.findOne.bind(this))
this.router.patch('/items/:id', LibraryItemController.middleware.bind(this), LibraryItemController.update.bind(this))
this.router.delete('/items/:id', LibraryItemController.middleware.bind(this), LibraryItemController.delete.bind(this))
@@ -83,27 +84,13 @@ class ApiController {
this.router.patch('/items/:id/cover', LibraryItemController.middleware.bind(this), LibraryItemController.updateCover.bind(this))
this.router.delete('/items/:id/cover', LibraryItemController.middleware.bind(this), LibraryItemController.removeCover.bind(this))
this.router.get('/items/:id/stream', LibraryItemController.middleware.bind(this), LibraryItemController.openStream.bind(this))
+ this.router.post('/items/:id/match', LibraryItemController.middleware.bind(this), LibraryItemController.match.bind(this))
+ this.router.patch('/items/:id/tracks', LibraryItemController.middleware.bind(this), LibraryItemController.updateTracks.bind(this))
this.router.post('/items/batch/delete', LibraryItemController.batchDelete.bind(this))
this.router.post('/items/batch/update', LibraryItemController.batchUpdate.bind(this))
this.router.post('/items/batch/get', LibraryItemController.batchGet.bind(this))
- //
- // Book Routes
- //
- this.router.get('/books', BookController.findAll.bind(this))
- this.router.get('/books/:id', BookController.findOne.bind(this))
- this.router.patch('/books/:id', BookController.update.bind(this))
- this.router.delete('/books/:id', BookController.delete.bind(this))
-
- this.router.delete('/books/all', BookController.deleteAll.bind(this))
- this.router.patch('/books/:id/tracks', BookController.updateTracks.bind(this))
- this.router.get('/books/:id/stream', BookController.openStream.bind(this))
- this.router.post('/books/:id/cover', BookController.uploadCover.bind(this))
- this.router.get('/books/:id/cover', BookController.getCover.bind(this))
- this.router.patch('/books/:id/coverfile', BookController.updateCoverFromFile.bind(this))
- this.router.post('/books/:id/match', BookController.match.bind(this))
-
//
// User Routes
//
diff --git a/server/Server.js b/server/Server.js
index 35053eae..2344f444 100644
--- a/server/Server.js
+++ b/server/Server.js
@@ -218,8 +218,6 @@ class Server {
})
// Client dynamic routes
- app.get('/audiobook/:id', (req, res) => res.sendFile(Path.join(distPath, 'index.html'))) // LEGACY
- app.get('/audiobook/:id/edit', (req, res) => res.sendFile(Path.join(distPath, 'index.html'))) // LEGACY
app.get('/item/:id', (req, res) => res.sendFile(Path.join(distPath, 'index.html')))
app.get('/item/:id/edit', (req, res) => res.sendFile(Path.join(distPath, 'index.html')))
app.get('/library/:library', (req, res) => res.sendFile(Path.join(distPath, 'index.html')))
diff --git a/server/controllers/BookController.js b/server/controllers/BookController.js
deleted file mode 100644
index eaa1c512..00000000
--- a/server/controllers/BookController.js
+++ /dev/null
@@ -1,279 +0,0 @@
-const Logger = require('../Logger')
-const { reqSupportsWebp } = require('../utils/index')
-
-class BookController {
- constructor() { }
-
- findAll(req, res) {
- var audiobooks = []
-
- if (req.query.q) {
- audiobooks = this.db.audiobooks.filter(ab => {
- return ab.isSearchMatch(req.query.q)
- }).map(ab => ab.toJSONMinified())
- } else {
- audiobooks = this.db.audiobooks.map(ab => ab.toJSONMinified())
- }
- res.json(audiobooks)
- }
-
- findOne(req, res) {
- var audiobook = this.db.audiobooks.find(a => a.id === req.params.id)
- if (!audiobook) return res.sendStatus(404)
-
- // Check user can access this audiobooks library
- if (!req.user.checkCanAccessLibrary(audiobook.libraryId)) {
- return res.sendStatus(403)
- }
-
- res.json(audiobook.toJSONExpanded())
- }
-
- async update(req, res) {
- if (!req.user.canUpdate) {
- Logger.warn('User attempted to update without permission', req.user)
- return res.sendStatus(403)
- }
- var audiobook = this.db.audiobooks.find(a => a.id === req.params.id)
- if (!audiobook) return res.sendStatus(404)
-
- // Book has cover and update is removing cover then purge cache
- if (audiobook.cover && req.body.book && (req.body.book.cover === '' || req.body.book.cover === null)) {
- await this.cacheManager.purgeCoverCache(audiobook.id)
- }
-
- var hasUpdates = audiobook.update(req.body)
- if (hasUpdates) {
- await this.db.updateAudiobook(audiobook)
- this.emitter('audiobook_updated', audiobook.toJSONExpanded())
- }
- res.json(audiobook.toJSON())
- }
-
- async delete(req, res) {
- if (!req.user.canDelete) {
- Logger.warn('User attempted to delete without permission', req.user)
- return res.sendStatus(403)
- }
- var audiobook = this.db.audiobooks.find(a => a.id === req.params.id)
- if (!audiobook) return res.sendStatus(404)
-
- await this.handleDeleteAudiobook(audiobook)
- res.sendStatus(200)
- }
-
- // DELETE: api/books/all
- async deleteAll(req, res) {
- if (!req.user.isRoot) {
- Logger.warn('User other than root attempted to delete all library items', req.user)
- return res.sendStatus(403)
- }
- Logger.info('Removing all Library Items')
- var success = await this.db.recreateLibraryItemsDb()
- if (success) res.sendStatus(200)
- else res.sendStatus(500)
- }
-
-
- // POST: api/books/batch/delete
- async batchDelete(req, res) {
- if (!req.user.canDelete) {
- Logger.warn('User attempted to delete without permission', req.user)
- return res.sendStatus(403)
- }
- var { audiobookIds } = req.body
- if (!audiobookIds || !audiobookIds.length) {
- return res.sendStatus(500)
- }
-
- var audiobooksToDelete = this.db.audiobooks.filter(ab => audiobookIds.includes(ab.id))
- if (!audiobooksToDelete.length) {
- return res.sendStatus(404)
- }
- for (let i = 0; i < audiobooksToDelete.length; i++) {
- Logger.info(`[ApiController] Deleting Audiobook "${audiobooksToDelete[i].title}"`)
- await this.handleDeleteAudiobook(audiobooksToDelete[i])
- }
- res.sendStatus(200)
- }
-
- // POST: api/books/batch/update
- async batchUpdate(req, res) {
- if (!req.user.canUpdate) {
- Logger.warn('User attempted to batch update without permission', req.user)
- return res.sendStatus(403)
- }
- var updatePayloads = req.body
- if (!updatePayloads || !updatePayloads.length) {
- return res.sendStatus(500)
- }
-
- var audiobooksUpdated = 0
- var audiobooks = updatePayloads.map((up) => {
- var audiobookUpdates = up.updates
- var ab = this.db.audiobooks.find(_ab => _ab.id === up.id)
- if (!ab) return null
- var hasUpdated = ab.update(audiobookUpdates)
- if (!hasUpdated) return null
- audiobooksUpdated++
- return ab
- }).filter(ab => ab)
-
- if (audiobooksUpdated) {
- Logger.info(`[ApiController] ${audiobooksUpdated} Audiobooks have updates`)
- for (let i = 0; i < audiobooks.length; i++) {
- await this.db.updateAudiobook(audiobooks[i])
- this.emitter('audiobook_updated', audiobooks[i].toJSONExpanded())
- }
- }
-
- res.json({
- success: true,
- updates: audiobooksUpdated
- })
- }
-
- // POST: api/books/batch/get
- async batchGet(req, res) {
- var bookIds = req.body.books || []
- if (!bookIds.length) {
- return res.status(403).send('Invalid payload')
- }
- var audiobooks = this.db.audiobooks.filter(ab => bookIds.includes(ab.id)).map((ab) => ab.toJSONExpanded())
- res.json(audiobooks)
- }
-
- // PATCH: api/books/:id/tracks
- async updateTracks(req, res) {
- if (!req.user.canUpdate) {
- Logger.warn('User attempted to update audiotracks without permission', req.user)
- return res.sendStatus(403)
- }
- var audiobook = this.db.audiobooks.find(a => a.id === req.params.id)
- if (!audiobook) return res.sendStatus(404)
- var orderedFileData = req.body.orderedFileData
- Logger.info(`Updating audiobook tracks called ${audiobook.id}`)
- audiobook.updateAudioTracks(orderedFileData)
- await this.db.updateAudiobook(audiobook)
- this.emitter('audiobook_updated', audiobook.toJSONExpanded())
- res.json(audiobook.toJSON())
- }
-
- // GET: api/books/:id/stream
- openStream(req, res) {
- var audiobook = this.db.audiobooks.find(a => a.id === req.params.id)
- if (!audiobook) return res.sendStatus(404)
-
- this.streamManager.openStreamApiRequest(res, req.user, audiobook)
- }
-
- // POST: api/books/:id/cover
- async uploadCover(req, res) {
- if (!req.user.canUpload || !req.user.canUpdate) {
- Logger.warn('User attempted to upload a cover without permission', req.user)
- return res.sendStatus(403)
- }
-
- var audiobookId = req.params.id
- var audiobook = this.db.audiobooks.find(ab => ab.id === audiobookId)
- if (!audiobook) {
- return res.status(404).send('Audiobook not found')
- }
-
- var result = null
- if (req.body && req.body.url) {
- Logger.debug(`[ApiController] Requesting download cover from url "${req.body.url}"`)
- result = await this.coverController.downloadCoverFromUrl(audiobook, req.body.url)
- } else if (req.files && req.files.cover) {
- Logger.debug(`[ApiController] Handling uploaded cover`)
- var coverFile = req.files.cover
- result = await this.coverController.uploadCover(audiobook, coverFile)
- } else {
- return res.status(400).send('Invalid request no file or url')
- }
-
- if (result && result.error) {
- return res.status(400).send(result.error)
- } else if (!result || !result.cover) {
- return res.status(500).send('Unknown error occurred')
- }
-
- await this.db.updateAudiobook(audiobook)
- this.emitter('audiobook_updated', audiobook.toJSONExpanded())
- res.json({
- success: true,
- cover: result.cover
- })
- }
-
- // PATCH api/books/:id/coverfile
- async updateCoverFromFile(req, res) {
- if (!req.user.canUpdate) {
- Logger.warn('User attempted to update without permission', req.user)
- return res.sendStatus(403)
- }
- var audiobook = this.db.audiobooks.find(a => a.id === req.params.id)
- if (!audiobook) return res.sendStatus(404)
-
- var coverFile = req.body
- var updated = await audiobook.setCoverFromFile(coverFile)
-
- if (updated) {
- await this.db.updateAudiobook(audiobook)
- await this.cacheManager.purgeCoverCache(audiobook.id)
- this.emitter('audiobook_updated', audiobook.toJSONExpanded())
- }
-
- if (updated) res.status(200).send('Cover updated successfully')
- else res.status(200).send('No update was made to cover')
- }
-
- // GET api/books/:id/cover
- async getCover(req, res) {
- let { query: { width, height, format }, params: { id } } = req
- var audiobook = this.db.audiobooks.find(a => a.id === id)
- if (!audiobook || !audiobook.book.cover) return res.sendStatus(404)
-
- // Check user can access this audiobooks library
- if (!req.user.checkCanAccessLibrary(audiobook.libraryId)) {
- return res.sendStatus(403)
- }
-
- // Temp fix for books without a full cover path
- if (audiobook.book.cover && !audiobook.book.coverFullPath) {
- var isFixed = audiobook.fixFullCoverPath()
- if (!isFixed) {
- Logger.warn(`[BookController] Failed to fix full cover path "${audiobook.book.cover}" for "${audiobook.book.title}"`)
- return res.sendStatus(404)
- }
- await this.db.updateEntity('audiobook', audiobook)
- }
-
- const options = {
- format: format || (reqSupportsWebp(req) ? 'webp' : 'jpeg'),
- height: height ? parseInt(height) : null,
- width: width ? parseInt(width) : null
- }
- return this.cacheManager.handleCoverCache(res, audiobook, options)
- }
-
- // POST api/books/:id/match
- async match(req, res) {
- if (!req.user.canUpdate) {
- Logger.warn('User attempted to match without permission', req.user)
- return res.sendStatus(403)
- }
- var audiobook = this.db.audiobooks.find(a => a.id === req.params.id)
- if (!audiobook) return res.sendStatus(404)
-
- // Check user can access this audiobooks library
- if (!req.user.checkCanAccessLibrary(audiobook.libraryId)) {
- return res.sendStatus(403)
- }
-
- var options = req.body || {}
- var matchResult = await this.scanner.quickMatchBook(audiobook, options)
- res.json(matchResult)
- }
-}
-module.exports = new BookController()
\ No newline at end of file
diff --git a/server/controllers/LibraryController.js b/server/controllers/LibraryController.js
index 911d3774..45edd679 100644
--- a/server/controllers/LibraryController.js
+++ b/server/controllers/LibraryController.js
@@ -230,7 +230,7 @@ class LibraryController {
res.json(libraryHelpers.getDistinctFilterDataNew(req.libraryItems))
}
- // api/libraries/:id/books/personalized
+ // api/libraries/:id/personalized
async getLibraryUserPersonalized(req, res) {
var libraryItems = req.libraryItems
var limitPerShelf = req.query.limit && !isNaN(req.query.limit) ? Number(req.query.limit) : 12
diff --git a/server/controllers/LibraryItemController.js b/server/controllers/LibraryItemController.js
index 22aa048f..a0aca65e 100644
--- a/server/controllers/LibraryItemController.js
+++ b/server/controllers/LibraryItemController.js
@@ -138,6 +138,26 @@ class LibraryItemController {
this.streamManager.openStreamApiRequest(res, req.user, req.libraryItem)
}
+ // POST api/items/:id/match
+ async match(req, res) {
+ var libraryItem = req.libraryItem
+
+ var options = req.body || {}
+ var matchResult = await this.scanner.quickMatchBook(libraryItem, options)
+ res.json(matchResult)
+ }
+
+ // PATCH: api/items/:id/tracks
+ async updateTracks(req, res) {
+ var libraryItem = req.libraryItem
+ var orderedFileData = req.body.orderedFileData
+ Logger.info(`Updating item tracks called ${libraryItem.id}`)
+ libraryItem.media.updateAudioTracks(orderedFileData)
+ await this.db.updateLibraryItem(libraryItem)
+ this.emitter('item_updated', libraryItem.toJSONExpanded())
+ res.json(libraryItem.toJSON())
+ }
+
// POST: api/items/batch/delete
async batchDelete(req, res) {
if (!req.user.canDelete) {
@@ -202,6 +222,18 @@ class LibraryItemController {
res.json(libraryItems)
}
+ // DELETE: api/items/all
+ async deleteAll(req, res) {
+ if (!req.user.isRoot) {
+ Logger.warn('User other than root attempted to delete all library items', req.user)
+ return res.sendStatus(403)
+ }
+ Logger.info('Removing all Library Items')
+ var success = await this.db.recreateLibraryItemsDb()
+ if (success) res.sendStatus(200)
+ else res.sendStatus(500)
+ }
+
middleware(req, res, next) {
var item = this.db.libraryItems.find(li => li.id === req.params.id)
diff --git a/server/controllers/MeController.js b/server/controllers/MeController.js
index b9b2b31f..fd84d382 100644
--- a/server/controllers/MeController.js
+++ b/server/controllers/MeController.js
@@ -18,16 +18,16 @@ class MeController {
// PATCH: api/me/audiobook/:id/reset-progress
async resetAudiobookProgress(req, res) {
- var audiobook = this.db.audiobooks.find(ab => ab.id === req.params.id)
- if (!audiobook) {
- return res.status(404).send('Audiobook not found')
+ var libraryItem = this.db.libraryItems.find(li => li.id === req.params.id)
+ if (!libraryItem) {
+ return res.status(404).send('Item not found')
}
- req.user.resetAudiobookProgress(audiobook)
+ req.user.resetAudiobookProgress(libraryItem)
await this.db.updateEntity('user', req.user)
- var userAudiobookData = req.user.audiobooks[audiobook.id]
+ var userAudiobookData = req.user.audiobooks[libraryItem.id]
if (userAudiobookData) {
- this.clientEmitter(req.user.id, 'current_user_audiobook_update', { id: audiobook.id, data: userAudiobookData })
+ this.clientEmitter(req.user.id, 'current_user_audiobook_update', { id: libraryItem.id, data: userAudiobookData })
}
this.clientEmitter(req.user.id, 'user_updated', req.user.toJSONForBrowser())
@@ -36,11 +36,11 @@ class MeController {
// PATCH: api/me/audiobook/:id
async updateAudiobookData(req, res) {
- var audiobook = this.db.audiobooks.find(ab => ab.id === req.params.id)
- if (!audiobook) {
- return res.status(404).send('Audiobook not found')
+ var libraryItem = this.db.libraryItems.find(ab => ab.id === req.params.id)
+ if (!libraryItem) {
+ return res.status(404).send('Item not found')
}
- var wasUpdated = req.user.updateAudiobookData(audiobook.id, req.body)
+ var wasUpdated = req.user.updateAudiobookData(libraryItem.id, req.body)
if (wasUpdated) {
await this.db.updateEntity('user', req.user)
this.clientEmitter(req.user.id, 'user_updated', req.user.toJSONForBrowser())
@@ -57,9 +57,9 @@ class MeController {
var shouldUpdate = false
userAbDataPayloads.forEach((userAbData) => {
- var audiobook = this.db.audiobooks.find(ab => ab.id === userAbData.audiobookId)
- if (audiobook) {
- var wasUpdated = req.user.updateAudiobookData(audiobook.id, userAbData)
+ var libraryItem = this.db.libraryItems.find(li => li.id === userAbData.audiobookId)
+ if (libraryItem) {
+ var wasUpdated = req.user.updateAudiobookData(libraryItem.id, userAbData)
if (wasUpdated) shouldUpdate = true
}
})
diff --git a/server/objects/User.js b/server/objects/User.js
index 2a946fde..6edc5b41 100644
--- a/server/objects/User.js
+++ b/server/objects/User.js
@@ -250,11 +250,11 @@ class User {
return madeUpdates
}
- resetAudiobookProgress(audiobook) {
- if (!this.audiobooks || !this.audiobooks[audiobook.id]) {
+ resetAudiobookProgress(libraryItem) {
+ if (!this.audiobooks || !this.audiobooks[libraryItem.id]) {
return false
}
- return this.updateAudiobookData(audiobook.id, {
+ return this.updateAudiobookData(libraryItem.id, {
progress: 0,
currentTime: 0,
isRead: false,
diff --git a/server/objects/entities/Book.js b/server/objects/entities/Book.js
index d9184670..1eb547c7 100644
--- a/server/objects/entities/Book.js
+++ b/server/objects/entities/Book.js
@@ -1,3 +1,4 @@
+const Path = require('path')
const Logger = require('../../Logger')
const BookMetadata = require('../metadata/BookMetadata')
const AudioFile = require('../files/AudioFile')
@@ -124,6 +125,27 @@ class Book {
return hasUpdates
}
+ updateAudioTracks(orderedFileData) {
+ var index = 1
+ this.audioFiles = orderedFileData.map((fileData) => {
+ var audioFile = this.audioFiles.find(af => af.ino === fileData.ino)
+ audioFile.manuallyVerified = true
+ audioFile.invalid = false
+ audioFile.error = null
+ if (fileData.exclude !== undefined) {
+ audioFile.exclude = !!fileData.exclude
+ }
+ if (audioFile.exclude) {
+ audioFile.index = -1
+ } else {
+ audioFile.index = index++
+ }
+ return audioFile
+ })
+
+ this.rebuildTracks()
+ }
+
updateCover(coverPath) {
coverPath = coverPath.replace(/\\/g, '/')
if (this.coverPath === coverPath) return false
diff --git a/server/objects/files/LibraryFile.js b/server/objects/files/LibraryFile.js
index 9cbdc5f9..b5296dc3 100644
--- a/server/objects/files/LibraryFile.js
+++ b/server/objects/files/LibraryFile.js
@@ -65,6 +65,7 @@ class LibraryFile {
this.metadata = fileMetadata
this.addedAt = Date.now()
this.updatedAt = Date.now()
+ console.log('Library file set from path', path, 'rel path', relPath)
}
}
module.exports = LibraryFile
\ No newline at end of file
diff --git a/server/objects/metadata/BookMetadata.js b/server/objects/metadata/BookMetadata.js
index 940362f0..95d2a5ca 100644
--- a/server/objects/metadata/BookMetadata.js
+++ b/server/objects/metadata/BookMetadata.js
@@ -135,7 +135,7 @@ class BookMetadata {
this.title = scanMediaData.title || null
this.subtitle = scanMediaData.subtitle || null
this.narrators = []
- this.publishYear = scanMediaData.publishYear || null
+ this.publishedYear = scanMediaData.publishedYear || null
this.description = scanMediaData.description || null
this.isbn = scanMediaData.isbn || null
this.asin = scanMediaData.asin || null
@@ -166,7 +166,7 @@ class BookMetadata {
},
{
tag: 'tagDate',
- key: 'publishYear'
+ key: 'publishedYear'
},
{
tag: 'tagSubtitle',
diff --git a/server/providers/Audible.js b/server/providers/Audible.js
index c50da3f4..b3779f49 100644
--- a/server/providers/Audible.js
+++ b/server/providers/Audible.js
@@ -16,7 +16,7 @@ class Audible {
author: authors ? authors.map(({ name }) => name).join(', ') : null,
narrator: narrators ? narrators.map(({ name }) => name).join(', ') : null,
publisher: publisher_name,
- publishYear: release_date ? release_date.split('-')[0] : null,
+ publishedYear: release_date ? release_date.split('-')[0] : null,
description: stripHtml(publisher_summary).result,
cover: this.getBestImageLink(product_images),
asin,
diff --git a/server/providers/GoogleBooks.js b/server/providers/GoogleBooks.js
index 0da3c309..0d78f0eb 100644
--- a/server/providers/GoogleBooks.js
+++ b/server/providers/GoogleBooks.js
@@ -23,7 +23,7 @@ class GoogleBooks {
subtitle: subtitle || null,
author: authors ? authors.join(', ') : null,
publisher,
- publishYear: publisherDate ? publisherDate.split('-')[0] : null,
+ publishedYear: publisherDate ? publisherDate.split('-')[0] : null,
description,
cover: imageLinks && imageLinks.thumbnail ? imageLinks.thumbnail : null,
genres: categories ? categories.join(', ') : null,
diff --git a/server/providers/OpenLibrary.js b/server/providers/OpenLibrary.js
index 3f4d4682..e22a3ac0 100644
--- a/server/providers/OpenLibrary.js
+++ b/server/providers/OpenLibrary.js
@@ -65,7 +65,7 @@ class OpenLibrary {
return {
title: doc.title,
author: doc.author_name ? doc.author_name.join(', ') : null,
- publishYear: this.parsePublishYear(doc, worksData),
+ publishedYear: this.parsePublishYear(doc, worksData),
edition: doc.cover_edition_key,
cover: doc.cover_edition_key ? `https://covers.openlibrary.org/b/OLID/${doc.cover_edition_key}-L.jpg` : null,
...worksData
diff --git a/server/providers/iTunes.js b/server/providers/iTunes.js
index 6e61e1f8..906c90db 100644
--- a/server/providers/iTunes.js
+++ b/server/providers/iTunes.js
@@ -65,7 +65,7 @@ class iTunes {
title: data.collectionName,
author: data.artistName,
description: stripHtml(data.description || '').result,
- publishYear: data.releaseDate ? data.releaseDate.split('-')[0] : null,
+ publishedYear: data.releaseDate ? data.releaseDate.split('-')[0] : null,
genres: data.primaryGenreName ? [data.primaryGenreName] : [],
cover: this.getCoverArtwork(data)
}
diff --git a/server/scanner/AudioFileScanner.js b/server/scanner/AudioFileScanner.js
index 691b9a48..743c6039 100644
--- a/server/scanner/AudioFileScanner.js
+++ b/server/scanner/AudioFileScanner.js
@@ -10,15 +10,15 @@ class AudioFileScanner {
constructor() { }
getTrackAndDiscNumberFromFilename(mediaMetadataFromScan, audioLibraryFile) {
- const { title, author, series, publishYear } = mediaMetadataFromScan
+ const { title, author, series, publishedYear } = mediaMetadataFromScan
const { filename, path } = audioLibraryFile.metadata
var partbasename = Path.basename(filename, Path.extname(filename))
- // Remove title, author, series, and publishYear from filename if there
+ // Remove title, author, series, and publishedYear from filename if there
if (title) partbasename = partbasename.replace(title, '')
if (author) partbasename = partbasename.replace(author, '')
if (series) partbasename = partbasename.replace(series, '')
- if (publishYear) partbasename = partbasename.replace(publishYear)
+ if (publishedYear) partbasename = partbasename.replace(publishedYear)
// Look for disc number
var discNumber = null
diff --git a/server/scanner/Scanner.js b/server/scanner/Scanner.js
index 298d7089..72033689 100644
--- a/server/scanner/Scanner.js
+++ b/server/scanner/Scanner.js
@@ -108,7 +108,7 @@ class Scanner {
}
}
}
- console.log('Finished library item scan', libraryItem.hasMediaFiles, hasUpdated)
+
if (!libraryItem.hasMediaFiles) { // Library Item is invalid
libraryItem.setInvalid()
hasUpdated = true
@@ -671,10 +671,10 @@ class Scanner {
}
}
- async quickMatchBook(audiobook, options = {}) {
+ async quickMatchBook(libraryItem, options = {}) {
var provider = options.provider || 'google'
- var searchTitle = options.title || audiobook.book._title
- var searchAuthor = options.author || audiobook.book._author
+ var searchTitle = options.title || libraryItem.media.metadata.title
+ var searchAuthor = options.author || libraryItem.media.metadata.authorName
var results = await this.bookFinder.search(provider, searchTitle, searchAuthor)
if (!results.length) {
@@ -686,40 +686,70 @@ class Scanner {
// Update cover if not set OR overrideCover flag
var hasUpdated = false
- if (matchData.cover && (!audiobook.book.cover || options.overrideCover)) {
- Logger.debug(`[BookController] Updating cover "${matchData.cover}"`)
- var coverResult = await this.coverController.downloadCoverFromUrl(audiobook, matchData.cover)
+ if (matchData.cover && (!libraryItem.media.coverPath || options.overrideCover)) {
+ Logger.debug(`[Scanner] Updating cover "${matchData.cover}"`)
+ var coverResult = await this.coverController.downloadCoverFromUrl(libraryItem, matchData.cover)
if (!coverResult || coverResult.error || !coverResult.cover) {
- Logger.warn(`[BookController] Match cover "${matchData.cover}" failed to use: ${coverResult ? coverResult.error : 'Unknown Error'}`)
+ Logger.warn(`[Scanner] Match cover "${matchData.cover}" failed to use: ${coverResult ? coverResult.error : 'Unknown Error'}`)
} else {
hasUpdated = true
}
}
- // Update book details if not set OR overrideDetails flag
- const detailKeysToUpdate = ['title', 'subtitle', 'author', 'narrator', 'publisher', 'publishYear', 'series', 'volumeNumber', 'asin', 'isbn']
+ // Update media metadata if not set OR overrideDetails flag
+ const detailKeysToUpdate = ['title', 'subtitle', 'narrator', 'publisher', 'publishedYear', 'asin', 'isbn']
const updatePayload = {}
for (const key in matchData) {
- if (matchData[key] && detailKeysToUpdate.includes(key) && (!audiobook.book[key] || options.overrideDetails)) {
- updatePayload[key] = matchData[key]
+ if (matchData[key] && detailKeysToUpdate.includes(key)) {
+ if (key === 'narrator') {
+ if ((!libraryItem.media.metadata.narratorName || options.overrideDetails)) {
+ updatePayload.narrators = [matchData[key]]
+ }
+ } else if ((!libraryItem.media.metadata[key] || options.overrideDetails)) {
+ updatePayload[key] = matchData[key]
+ }
}
}
+ // Add or set author if not set
+ if (matchData.author && !libraryItem.media.metadata.authorName) {
+ var author = this.db.authors.find(au => au.checkNameEquals(matchData.author))
+ if (!author) {
+ author = new Author()
+ author.setData({ name: matchData.author })
+ await this.db.insertEntity('author', author)
+ this.emitter('author_added', author)
+ }
+ updatePayload.authors = [author.toJSONMinimal()]
+ }
+
+ // Add or set series if not set
+ if (matchData.series && !libraryItem.media.metadata.seriesName) {
+ var seriesItem = this.db.series.find(au => au.checkNameEquals(matchData.series))
+ if (!seriesItem) {
+ seriesItem = new Series()
+ seriesItem.setData({ name: matchData.series })
+ await this.db.insertEntity('series', seriesItem)
+ this.emitter('series_added', seriesItem)
+ }
+ updatePayload.series = [seriesItem.toJSONMinimal(matchData.volumeNumber)]
+ }
+
if (Object.keys(updatePayload).length) {
- Logger.debug('[BookController] Updating details', updatePayload)
- if (audiobook.update({ book: updatePayload })) {
+ Logger.debug('[Scanner] Updating details', updatePayload)
+ if (libraryItem.media.update({ metadata: updatePayload })) {
hasUpdated = true
}
}
if (hasUpdated) {
- await this.db.updateAudiobook(audiobook)
- this.emitter('audiobook_updated', audiobook.toJSONExpanded())
+ await this.db.updateLibraryItem(libraryItem)
+ this.emitter('item_updated', libraryItem.toJSONExpanded())
}
return {
updated: hasUpdated,
- audiobook: audiobook.toJSONExpanded()
+ libraryItem: libraryItem.toJSONExpanded()
}
}
diff --git a/server/utils/abmetadataGenerator.js b/server/utils/abmetadataGenerator.js
index 21c4be5c..974a9202 100644
--- a/server/utils/abmetadataGenerator.js
+++ b/server/utils/abmetadataGenerator.js
@@ -8,7 +8,7 @@ const bookKeyMap = {
subtitle: 'subtitle',
author: 'authorFL',
narrator: 'narratorFL',
- publishYear: 'publishYear',
+ publishedYear: 'publishedYear',
publisher: 'publisher',
description: 'description',
isbn: 'isbn',
diff --git a/server/utils/dbMigration.js b/server/utils/dbMigration.js
index 1437b0e0..574cc289 100644
--- a/server/utils/dbMigration.js
+++ b/server/utils/dbMigration.js
@@ -75,7 +75,6 @@ function makeSeriesFromOldAb({ series, 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, '')
}
@@ -156,6 +155,7 @@ function makeLibraryItemFromOldAb(audiobook) {
var bookEntity = new Book()
var bookMetadata = new BookMetadata(audiobook.book)
+ bookMetadata.publishedYear = audiobook.book.publishYear || null
if (audiobook.book.narrator) {
bookMetadata.narrators = audiobook.book._narratorsList
}
diff --git a/server/utils/ffmpegHelpers.js b/server/utils/ffmpegHelpers.js
index 724eb317..fc927f57 100644
--- a/server/utils/ffmpegHelpers.js
+++ b/server/utils/ffmpegHelpers.js
@@ -47,7 +47,7 @@ async function writeMetadataFile(audiobook, outputPath) {
`title=${audiobook.title}`,
`artist=${audiobook.authorFL}`,
`album_artist=${audiobook.authorFL}`,
- `date=${audiobook.book.publishYear || ''}`,
+ `date=${audiobook.book.publishedYear || ''}`,
`description=${audiobook.book.description}`,
`genre=${audiobook.book._genres.join(';')}`,
`comment=Audiobookshelf v${package.version}`
diff --git a/server/utils/nfoGenerator.js b/server/utils/nfoGenerator.js
index d822fbd3..da21deb8 100644
--- a/server/utils/nfoGenerator.js
+++ b/server/utils/nfoGenerator.js
@@ -29,7 +29,7 @@ async function generate(audiobook, nfoFilename = 'metadata.nfo') {
'Narrator': book.narrator,
'Series': book.series,
'Volume Number': book.volumeNumber,
- 'Publish Year': book.publishYear,
+ 'Publish Year': book.publishedYear,
'Genre': book.genres ? book.genres.join(', ') : '',
'Duration': audiobook.durationPretty,
'Chapters': jsonObj.chapters.length
diff --git a/server/utils/parseOpfMetadata.js b/server/utils/parseOpfMetadata.js
index 276f1682..8a9bb4f3 100644
--- a/server/utils/parseOpfMetadata.js
+++ b/server/utils/parseOpfMetadata.js
@@ -113,7 +113,7 @@ module.exports.parseOpfMetadataXML = async (xml) => {
title: fetchTitle(metadata),
author: fetchCreator(creators, 'aut'),
narrator: fetchNarrators(creators, metadata),
- publishYear: fetchDate(metadata),
+ publishedYear: fetchDate(metadata),
publisher: fetchPublisher(metadata),
isbn: fetchISBN(metadata),
description: fetchDescription(metadata),
diff --git a/server/utils/scandir.js b/server/utils/scandir.js
index 32bc52cf..2582cd95 100644
--- a/server/utils/scandir.js
+++ b/server/utils/scandir.js
@@ -119,28 +119,16 @@ function groupFileItemsIntoLibraryItemDirs(fileItems) {
return libraryItemGroup
}
-function cleanFileObjects(libraryItemPath, libraryItemRelPath, files) {
+function cleanFileObjects(libraryItemPath, folderPath, files) {
return Promise.all(files.map(async (file) => {
var filePath = Path.posix.join(libraryItemPath, file)
- var relFilePath = Path.posix.join(libraryItemRelPath, file)
+ var relFilePath = filePath.replace(folderPath, '')
var newLibraryFile = new LibraryFile()
await newLibraryFile.setDataFromPath(filePath, relFilePath)
return newLibraryFile
}))
}
-function getFileType(ext) {
- var ext_cleaned = ext.toLowerCase()
- if (ext_cleaned.startsWith('.')) ext_cleaned = ext_cleaned.slice(1)
- if (globals.SupportedAudioTypes.includes(ext_cleaned)) return 'audio'
- if (globals.SupportedImageTypes.includes(ext_cleaned)) return 'image'
- if (globals.SupportedEbookTypes.includes(ext_cleaned)) return 'ebook'
- if (ext_cleaned === 'nfo') return 'info'
- if (ext_cleaned === 'txt') return 'text'
- if (ext_cleaned === 'opf') return 'opf'
- return 'unknown'
-}
-
// Scan folder
async function scanFolder(libraryMediaType, folder, serverSettings = {}) {
var folderPath = folder.fullPath.replace(/\\/g, '/')
@@ -164,7 +152,7 @@ async function scanFolder(libraryMediaType, folder, serverSettings = {}) {
for (const libraryItemPath in libraryItemGrouping) {
var libraryItemData = getDataFromMediaDir(libraryMediaType, folderPath, libraryItemPath, serverSettings)
- var fileObjs = await cleanFileObjects(libraryItemData.path, libraryItemData.relPath, libraryItemGrouping[libraryItemPath])
+ var fileObjs = await cleanFileObjects(libraryItemData.path, folderPath, libraryItemGrouping[libraryItemPath])
var libraryItemFolderStats = await getFileTimestampsWithIno(libraryItemData.path)
items.push({
folderId: folder.id,
@@ -236,7 +224,7 @@ function getBookDataFromDir(folderPath, relPath, parseSubtitle = false) {
}
}
- var publishYear = null
+ var publishedYear = null
// If Title is of format 1999 OR (1999) - Title, then use 1999 as publish year
var publishYearMatch = title.match(/^(\(?[0-9]{4}\)?) - (.+)/)
if (publishYearMatch && publishYearMatch.length > 2 && publishYearMatch[1]) {
@@ -245,7 +233,7 @@ function getBookDataFromDir(folderPath, relPath, parseSubtitle = false) {
publishYearMatch[1] = publishYearMatch[1].slice(1, -1)
}
if (!isNaN(publishYearMatch[1])) {
- publishYear = publishYearMatch[1]
+ publishedYear = publishYearMatch[1]
title = publishYearMatch[2]
}
}
@@ -267,7 +255,7 @@ function getBookDataFromDir(folderPath, relPath, parseSubtitle = false) {
subtitle,
series,
sequence: volumeNumber,
- publishYear,
+ publishedYear,
},
relPath: relPath, // relative audiobook path i.e. /Author Name/Book Name/..
path: Path.posix.join(folderPath, relPath) // i.e. /audiobook/Author Name/Book Name/..
@@ -281,7 +269,7 @@ function getDataFromMediaDir(libraryMediaType, folderPath, relPath, serverSettin
async function getLibraryItemFileData(libraryMediaType, folder, libraryItemPath, serverSettings = {}) {
- var fileItems = await recurseFiles(libraryItemPath, folder.fullPath)
+ var fileItems = await recurseFiles(libraryItemPath)
libraryItemPath = libraryItemPath.replace(/\\/g, '/')
var folderFullPath = folder.fullPath.replace(/\\/g, '/')
|