From 03963aa9a12124be5fafca7355000ade32f75891 Mon Sep 17 00:00:00 2001 From: advplyr Date: Fri, 15 Oct 2021 20:31:00 -0500 Subject: [PATCH] change color of book read icon #105, basic .pdf reader #107, fix: cover path updating properly #102, step forward/backward from book edit modal #100, add all files tab to edit modal #99, select input auto submit on blur #98 --- client/components/app/BookShelf.vue | 7 +- client/components/app/BookShelfRow.vue | 7 +- client/components/app/PdfReader.vue | 74 ++++++++++++ client/components/app/Reader.vue | 60 ++++++---- client/components/cards/BookCard.vue | 3 +- client/components/modals/EditModal.vue | 52 +++++++++ client/components/modals/edit-tabs/Cover.vue | 22 +++- .../components/modals/edit-tabs/Details.vue | 2 - client/components/modals/edit-tabs/Files.vue | 21 ++++ client/components/modals/edit-tabs/Tracks.vue | 2 - client/components/tables/AllFilesTable.vue | 109 ++++++++++++++++++ client/components/tables/OtherFilesTable.vue | 15 ++- client/components/ui/InputDropdown.vue | 3 - client/components/ui/MultiSelect.vue | 4 + client/components/ui/ReadIconBtn.vue | 2 +- client/package-lock.json | 81 ++++++++++++- client/package.json | 3 +- client/pages/audiobook/_id/index.vue | 1 + client/pages/batch/index.vue | 51 +++++++- client/pages/index.vue | 4 +- .../pages/library/_library/bookshelf/_id.vue | 1 + client/store/index.js | 15 ++- package.json | 2 +- server/ApiController.js | 21 ++++ server/DownloadManager.js | 3 + server/objects/Audiobook.js | 26 ++++- server/objects/Book.js | 8 +- 27 files changed, 545 insertions(+), 54 deletions(-) create mode 100644 client/components/app/PdfReader.vue create mode 100644 client/components/modals/edit-tabs/Files.vue create mode 100644 client/components/tables/AllFilesTable.vue diff --git a/client/components/app/BookShelf.vue b/client/components/app/BookShelf.vue index f442a276..9a70a2aa 100644 --- a/client/components/app/BookShelf.vue +++ b/client/components/app/BookShelf.vue @@ -23,7 +23,7 @@
@@ -138,6 +138,11 @@ export default { } }, methods: { + editBook(audiobook) { + var bookIds = this.entities.map((e) => e.id) + this.$store.commit('setBookshelfBookIds', bookIds) + this.$store.commit('showEditModal', audiobook) + }, clickGroup(group) { this.$emit('update:selectedSeries', group.name) }, diff --git a/client/components/app/BookShelfRow.vue b/client/components/app/BookShelfRow.vue index 07e53dc3..cd36a852 100644 --- a/client/components/app/BookShelfRow.vue +++ b/client/components/app/BookShelfRow.vue @@ -4,7 +4,7 @@
@@ -53,6 +53,11 @@ export default { } }, methods: { + editBook(audiobook) { + var bookIds = this.shelf.books.map((e) => e.id) + this.$store.commit('setBookshelfBookIds', bookIds) + this.$store.commit('showEditModal', audiobook) + }, scrolled() { clearTimeout(this.scrollTimer) this.scrollTimer = setTimeout(() => { diff --git a/client/components/app/PdfReader.vue b/client/components/app/PdfReader.vue new file mode 100644 index 00000000..718b1240 --- /dev/null +++ b/client/components/app/PdfReader.vue @@ -0,0 +1,74 @@ + + + \ No newline at end of file diff --git a/client/components/app/Reader.vue b/client/components/app/Reader.vue index 0d091594..0a44ee9a 100644 --- a/client/components/app/Reader.vue +++ b/client/components/app/Reader.vue @@ -14,7 +14,7 @@
-
+
chevron_left
@@ -30,11 +30,17 @@
-
+
+ +
+ +
+ +
{{ ebookType }}
@@ -55,7 +61,9 @@ export default { author: '', progress: 0, hasNext: true, - hasPrev: false + hasPrev: false, + ebookType: '', + ebookUrl: '' } }, watch: { @@ -97,28 +105,23 @@ export default { epubEbook() { return this.ebooks.find((eb) => eb.ext === '.epub') }, - epubPath() { - return this.epubEbook ? this.epubEbook.path : null - }, mobiEbook() { return this.ebooks.find((eb) => eb.ext === '.mobi' || eb.ext === '.azw3') }, - mobiPath() { - return this.mobiEbook ? this.mobiEbook.path : null - }, - mobiUrl() { - if (!this.mobiPath) return null - return `/ebook/${this.libraryId}/${this.folderId}/${this.mobiPath}` - }, - url() { - if (!this.epubPath) return null - return `/ebook/${this.libraryId}/${this.folderId}/${this.epubPath}` + pdfEbook() { + return this.ebooks.find((eb) => eb.ext === '.pdf') }, userToken() { return this.$store.getters['user/getToken'] + }, + selectedAudiobookFile() { + return this.$store.state.selectedAudiobookFile } }, methods: { + getEbookUrl(path) { + return `/ebook/${this.libraryId}/${this.folderId}/${path}` + }, changedChapter() { if (this.rendition) { this.rendition.display(this.selectedChapter) @@ -156,11 +159,28 @@ export default { }, init() { this.registerListeners() - - if (this.epubEbook) { + if (this.selectedAudiobookFile) { + this.ebookUrl = this.getEbookUrl(this.selectedAudiobookFile.path) + if (this.selectedAudiobookFile.ext === '.pdf') { + this.ebookType = 'pdf' + } else if (this.selectedAudiobookFile.ext === '.mobi' || this.selectedAudiobookFile.ext === '.azw3') { + this.ebookType = 'mobi' + this.initMobi() + } else if (this.selectedAudiobookFile.ext === '.epub') { + this.ebookType = 'epub' + this.initEpub() + } + } else if (this.epubEbook) { + this.ebookType = 'epub' + this.ebookUrl = this.getEbookUrl(this.epubEbook.path) this.initEpub() } else if (this.mobiEbook) { + this.ebookType = 'mobi' + this.ebookUrl = this.getEbookUrl(this.mobiEbook.path) this.initMobi() + } else if (this.pdfEbook) { + this.ebookType = 'pdf' + this.ebookUrl = this.getEbookUrl(this.pdfEbook.path) } }, addHtmlCss() { @@ -219,7 +239,7 @@ export default { }, async initMobi() { // Fetch mobi file as blob - var buff = await this.$axios.$get(this.mobiUrl, { + var buff = await this.$axios.$get(this.ebookUrl, { responseType: 'blob' }) var reader = new FileReader() @@ -251,7 +271,7 @@ export default { // Authorization: `Bearer ${this.userToken}` // } // }) - var book = ePub(this.url) + var book = ePub(this.ebookUrl) this.book = book this.rendition = book.renderTo('viewer', { diff --git a/client/components/cards/BookCard.vue b/client/components/cards/BookCard.vue index 3a6d5079..ed007d85 100644 --- a/client/components/cards/BookCard.vue +++ b/client/components/cards/BookCard.vue @@ -228,7 +228,8 @@ export default { this.$root.socket.emit('open_stream', this.audiobookId) }, editClick() { - this.$store.commit('showEditModal', this.audiobook) + // this.$store.commit('showEditModal', this.audiobook) + this.$emit('edit', this.audiobook) }, clickCard(e) { if (this.isSelectionMode) { diff --git a/client/components/modals/EditModal.vue b/client/components/modals/EditModal.vue index 7de002d4..85e799c9 100644 --- a/client/components/modals/EditModal.vue +++ b/client/components/modals/EditModal.vue @@ -10,6 +10,14 @@
{{ tab.title }}
+ +
+
arrow_back_ios
+
+
+
arrow_forward_ios
+
+
@@ -51,6 +59,11 @@ export default { title: 'Chapters', component: 'modals-edit-tabs-chapters' }, + { + id: 'files', + title: 'Files', + component: 'modals-edit-tabs-files' + }, { id: 'download', title: 'Download', @@ -68,6 +81,7 @@ export default { this.show = false return } + if (!availableTabIds.includes(this.selectedTab)) { this.selectedTab = availableTabIds[0] } @@ -137,9 +151,44 @@ export default { }, title() { return this.book.title || 'No Title' + }, + bookshelfBookIds() { + return this.$store.state.bookshelfBookIds || [] + }, + currentBookshelfIndex() { + if (!this.bookshelfBookIds.length) return 0 + return this.bookshelfBookIds.findIndex((bid) => bid === this.selectedAudiobookId) + }, + canGoPrev() { + return this.bookshelfBookIds.length && this.currentBookshelfIndex > 0 + }, + canGoNext() { + return this.bookshelfBookIds.length && this.currentBookshelfIndex < this.bookshelfBookIds.length - 1 } }, methods: { + goPrevBook() { + if (this.currentBookshelfIndex - 1 < 0) return + var prevBookId = this.bookshelfBookIds[this.currentBookshelfIndex - 1] + var prevBook = this.$store.getters['audiobooks/getAudiobook'](prevBookId) + if (prevBook) { + this.$store.commit('showEditModalOnTab', { audiobook: prevBook, tab: this.selectedTab }) + this.$nextTick(this.init) + } else { + console.error('Book not found', prevBookId) + } + }, + goNextBook() { + if (this.currentBookshelfIndex >= this.bookshelfBookIds.length) return + var nextBookId = this.bookshelfBookIds[this.currentBookshelfIndex + 1] + var nextBook = this.$store.getters['audiobooks/getAudiobook'](nextBookId) + if (nextBook) { + this.$store.commit('showEditModalOnTab', { audiobook: nextBook, tab: this.selectedTab }) + this.$nextTick(this.init) + } else { + console.error('Book not found', nextBookId) + } + }, selectTab(tab) { this.selectedTab = tab }, @@ -155,9 +204,12 @@ export default { }, async fetchFull() { try { + this.processing = true this.audiobook = await this.$axios.$get(`/api/audiobook/${this.selectedAudiobookId}`) + this.processing = false } catch (error) { console.error('Failed to fetch audiobook', this.selectedAudiobookId, error) + this.processing = false this.show = false } } diff --git a/client/components/modals/edit-tabs/Cover.vue b/client/components/modals/edit-tabs/Cover.vue index a74c10d9..806ef3ce 100644 --- a/client/components/modals/edit-tabs/Cover.vue +++ b/client/components/modals/edit-tabs/Cover.vue @@ -31,7 +31,7 @@