From dc8178769b40b45b54177c5fbe08e04cfdcbb883 Mon Sep 17 00:00:00 2001 From: advplyr Date: Tue, 31 Oct 2023 16:00:08 -0500 Subject: [PATCH 1/6] Fix:Series page sort order by name #925 --- components/bookshelf/LazyBookshelf.vue | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/components/bookshelf/LazyBookshelf.vue b/components/bookshelf/LazyBookshelf.vue index 5c2cd16a..4b082246 100644 --- a/components/bookshelf/LazyBookshelf.vue +++ b/components/bookshelf/LazyBookshelf.vue @@ -367,8 +367,14 @@ export default { this.handleScroll(scrollTop) }, buildSearchParams() { - if (this.page === 'search' || this.page === 'series' || this.page === 'collections') { + if (this.page === 'search' || this.page === 'collections') { return '' + } else if (this.page === 'series') { + // Sort by name ascending + let searchParams = new URLSearchParams() + searchParams.set('sort', 'name') + searchParams.set('desc', 0) + return searchParams.toString() } let searchParams = new URLSearchParams() From 04e468b43da66304fe231f70a6214126c054f637 Mon Sep 17 00:00:00 2001 From: advplyr Date: Tue, 31 Oct 2023 16:20:28 -0500 Subject: [PATCH 2/6] Fix:Android seeking from notification widget on multi-track books #894 --- .../audiobookshelf/app/player/MediaSessionCallback.kt | 3 ++- .../app/player/PlayerNotificationService.kt | 10 +++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/android/app/src/main/java/com/audiobookshelf/app/player/MediaSessionCallback.kt b/android/app/src/main/java/com/audiobookshelf/app/player/MediaSessionCallback.kt index cc2ba1f6..f7e3c89a 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/player/MediaSessionCallback.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/player/MediaSessionCallback.kt @@ -86,7 +86,8 @@ class MediaSessionCallback(var playerNotificationService:PlayerNotificationServi } override fun onSeekTo(pos: Long) { - playerNotificationService.seekPlayer(pos) + val currentTrackStartOffset = playerNotificationService.getCurrentTrackStartOffsetMs() + playerNotificationService.seekPlayer(currentTrackStartOffset + pos) } private fun onChangeSpeed() { diff --git a/android/app/src/main/java/com/audiobookshelf/app/player/PlayerNotificationService.kt b/android/app/src/main/java/com/audiobookshelf/app/player/PlayerNotificationService.kt index 07a2373a..16e0f19b 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/player/PlayerNotificationService.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/player/PlayerNotificationService.kt @@ -652,16 +652,20 @@ class PlayerNotificationService : MediaBrowserServiceCompat() { } } - fun getCurrentTime() : Long { + fun getCurrentTrackStartOffsetMs() : Long { return if (currentPlayer.mediaItemCount > 1) { val windowIndex = currentPlayer.currentMediaItemIndex val currentTrackStartOffset = currentPlaybackSession?.getTrackStartOffsetMs(windowIndex) ?: 0L - currentPlayer.currentPosition + currentTrackStartOffset + currentTrackStartOffset } else { - currentPlayer.currentPosition + 0 } } + fun getCurrentTime() : Long { + return currentPlayer.currentPosition + getCurrentTrackStartOffsetMs() + } + fun getCurrentTimeSeconds() : Double { return getCurrentTime() / 1000.0 } From fc7af6d1fcd1645ec637d4022c49177c10e521e2 Mon Sep 17 00:00:00 2001 From: advplyr Date: Thu, 2 Nov 2023 16:10:55 -0500 Subject: [PATCH 3/6] Add:Send ebook to device button #909 --- components/connection/ServerConnectForm.vue | 3 +- components/modals/Dialog.vue | 2 +- layouts/default.vue | 3 +- pages/item/_id/index.vue | 48 +++++++++++++++++++++ store/libraries.js | 6 ++- 5 files changed, 58 insertions(+), 4 deletions(-) diff --git a/components/connection/ServerConnectForm.vue b/components/connection/ServerConnectForm.vue index c2909281..d6b1d8f2 100644 --- a/components/connection/ServerConnectForm.vue +++ b/components/connection/ServerConnectForm.vue @@ -400,12 +400,13 @@ export default { this.setUserAndConnection(payload) } }, - async setUserAndConnection({ user, userDefaultLibraryId, serverSettings }) { + async setUserAndConnection({ user, userDefaultLibraryId, serverSettings, ereaderDevices }) { if (!user) return console.log('Successfully logged in', JSON.stringify(user)) this.$store.commit('setServerSettings', serverSettings) + this.$store.commit('libraries/setEReaderDevices', ereaderDevices) // Set library - Use last library if set and available fallback to default user library var lastLibraryId = await this.$localStore.getLastLibraryId() diff --git a/components/modals/Dialog.vue b/components/modals/Dialog.vue index 9fa46c18..9086e3a2 100644 --- a/components/modals/Dialog.vue +++ b/components/modals/Dialog.vue @@ -1,7 +1,7 @@ @@ -175,11 +180,13 @@ export default { }, data() { return { + processing: false, resettingProgress: false, isProcessingReadUpdate: false, showSelectLocalFolder: false, showMoreMenu: false, showDetailsModal: false, + showSendEbookDevicesModal: false, showFullscreenCover: false, coverRgb: 'rgb(55, 56, 56)', coverBgIsLight: false, @@ -430,6 +437,14 @@ export default { value: 'playlist', icon: 'playlist_add' }) + + if (this.ebookFile && this.$store.state.libraries.ereaderDevices?.length) { + items.push({ + text: 'Send ebook to device', + value: 'sendEbook', + icon: 'send' + }) + } } if (this.showRSSFeedOption) { @@ -464,6 +479,15 @@ export default { return items }, + ereaderDeviceItems() { + if (!this.ebookFile || !this.$store.state.libraries.ereaderDevices?.length) return [] + return this.$store.state.libraries.ereaderDevices.map((d) => { + return { + text: d.name, + value: d.name + } + }) + }, coverWidth() { let width = this.windowWidth - 94 if (width > 325) return 325 @@ -543,8 +567,31 @@ export default { this.deleteLocalItem() } else if (action === 'rssFeed') { this.clickRSSFeed() + } else if (action === 'sendEbook') { + this.showSendEbookDevicesModal = true } }, + sendEbookToDeviceAction(deviceName) { + this.showSendEbookDevicesModal = false + + const payload = { + libraryItemId: this.serverLibraryItemId, + deviceName + } + this.processing = true + this.$nativeHttp + .post(`/api/emails/send-ebook-to-device`, payload) + .then(() => { + this.$toast.success('Ebook sent successfully') + }) + .catch((error) => { + console.error('Failed to send ebook to device', error) + this.$toast.error('Failed to send ebook to device') + }) + .finally(() => { + this.processing = false + }) + }, clickRSSFeed() { this.$store.commit('globals/setRSSFeedOpenCloseModal', { id: this.serverLibraryItemId, @@ -555,6 +602,7 @@ export default { }) }, moreButtonPress() { + this.showSendEbookDevicesModal = false this.showMoreMenu = true }, readBook() { diff --git a/store/libraries.js b/store/libraries.js index 9582653e..602c8e1c 100644 --- a/store/libraries.js +++ b/store/libraries.js @@ -7,7 +7,8 @@ export const state = () => ({ showModal: false, issues: 0, filterData: null, - numUserPlaylists: 0 + numUserPlaylists: 0, + ereaderDevices: [] }) export const getters = { @@ -177,5 +178,8 @@ export const mutations = { if (genre && !state.filterData.genres.includes(genre)) state.filterData.genres.push(genre) }) } + }, + setEReaderDevices(state, ereaderDevices) { + state.ereaderDevices = ereaderDevices } } \ No newline at end of file From 74b488ad0f00235642cfb987b775da1af5adfb9c Mon Sep 17 00:00:00 2001 From: advplyr Date: Fri, 3 Nov 2023 13:00:45 -0500 Subject: [PATCH 4/6] Update playlist table design to include progress bar on items #914 --- components/tables/playlist/ItemTableRow.vue | 57 ++++++++++--------- .../tables/playlist/PlaylistItemsTable.vue | 6 +- pages/playlist/_id.vue | 8 +-- 3 files changed, 37 insertions(+), 34 deletions(-) diff --git a/components/tables/playlist/ItemTableRow.vue b/components/tables/playlist/ItemTableRow.vue index 2e054442..c2a46e7b 100644 --- a/components/tables/playlist/ItemTableRow.vue +++ b/components/tables/playlist/ItemTableRow.vue @@ -1,22 +1,25 @@ @@ -30,10 +33,7 @@ export default { } }, data() { - return { - isProcessingReadUpdate: false, - processingRemove: false - } + return {} }, computed: { libraryItem() { @@ -92,12 +92,6 @@ export default { coverWidth() { return 50 }, - isMissing() { - return this.libraryItem.isMissing - }, - isInvalid() { - return this.libraryItem.isInvalid - }, showPlayBtn() { return !this.isMissing && !this.isInvalid && (this.tracks.length || this.episode) }, @@ -107,6 +101,15 @@ export default { }, streamIsPlaying() { return this.$store.state.playerIsPlaying && this.isStreaming + }, + userItemProgress() { + return this.$store.getters['user/getUserMediaProgress'](this.libraryItem.id, this.episodeId) + }, + userIsFinished() { + return !!this.userItemProgress?.isFinished + }, + progressPercent() { + return this.userItemProgress ? Math.max(Math.min(1, this.userItemProgress.progress), 0) : 0 } }, methods: { diff --git a/components/tables/playlist/PlaylistItemsTable.vue b/components/tables/playlist/PlaylistItemsTable.vue index 9a2d5ce0..292fe270 100644 --- a/components/tables/playlist/PlaylistItemsTable.vue +++ b/components/tables/playlist/PlaylistItemsTable.vue @@ -1,7 +1,7 @@ @@ -67,7 +72,12 @@ export default { } }, data() { - return {} + return { + showMoreMenu: false, + processing: false, + selectedLibraryItem: null, + selectedEpisode: null + } }, computed: { bookCoverAspectRatio() { @@ -101,6 +111,11 @@ export default { } }, methods: { + showMore(playlistItem) { + this.selectedLibraryItem = playlistItem.libraryItem + this.selectedEpisode = playlistItem.episode + this.showMoreMenu = true + }, clickPlay() { const nextItem = this.playableItems.find((i) => { const prog = this.$store.getters['user/getUserMediaProgress'](i.libraryItemId, i.episodeId) From 087e8553c4cbd80c29dfe4bde4840fe3168b22b9 Mon Sep 17 00:00:00 2001 From: advplyr Date: Sat, 4 Nov 2023 16:08:19 -0500 Subject: [PATCH 6/6] Update:Bookmarks modal is not closed on updating/deleting and does not show a toast #882 --- components/modals/BookmarksModal.vue | 12 +++++------- store/user.js | 16 ++++++++++++++++ 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/components/modals/BookmarksModal.vue b/components/modals/BookmarksModal.vue index 1c4e0615..e481c1e7 100644 --- a/components/modals/BookmarksModal.vue +++ b/components/modals/BookmarksModal.vue @@ -105,30 +105,28 @@ export default { this.$nativeHttp .delete(`/api/me/item/${this.libraryItemId}/bookmark/${bm.time}`) .then(() => { - this.$toast.success('Bookmark removed') + this.$store.commit('user/deleteBookmark', { libraryItemId: this.libraryItemId, time: bm.time }) }) .catch((error) => { this.$toast.error(`Failed to remove bookmark`) console.error(error) }) - this.show = false }, async clickBookmark(bm) { await this.$hapticsImpact() this.$emit('select', bm) }, submitUpdateBookmark(updatedBookmark) { - var bookmark = { ...updatedBookmark } this.$nativeHttp - .patch(`/api/me/item/${this.libraryItemId}/bookmark`, bookmark) - .then(() => { - this.$toast.success('Bookmark updated') + .patch(`/api/me/item/${this.libraryItemId}/bookmark`, updatedBookmark) + .then((bookmark) => { + this.$store.commit('user/updateBookmark', bookmark) + this.showBookmarkTitleInput = false }) .catch((error) => { this.$toast.error(`Failed to update bookmark`) console.error(error) }) - this.show = false }, submitCreateBookmark() { if (!this.newBookmarkTitle) { diff --git a/store/user.js b/store/user.js index a4837a0f..aa69588e 100644 --- a/store/user.js +++ b/store/user.js @@ -145,5 +145,21 @@ export const mutations = { setSettings(state, settings) { if (!settings) return state.settings = settings + }, + updateBookmark(state, bookmark) { + if (!state.user?.bookmarks) return + state.user.bookmarks = state.user.bookmarks.map((bm) => { + if (bm.libraryItemId === bookmark.libraryItemId && bm.time === bookmark.time) { + return bookmark + } + return bm + }) + }, + deleteBookmark(state, { libraryItemId, time }) { + if (!state.user?.bookmarks) return + state.user.bookmarks = state.user.bookmarks.filter(bm => { + if (bm.libraryItemId === libraryItemId && bm.time === time) return false + return true + }) } } \ No newline at end of file