+
diff --git a/components/modals/bookmarks/BookmarkItem.vue b/components/modals/bookmarks/BookmarkItem.vue
new file mode 100644
index 00000000..c470c68f
--- /dev/null
+++ b/components/modals/bookmarks/BookmarkItem.vue
@@ -0,0 +1,43 @@
+
+
+
{{ highlight ? 'bookmark' : 'bookmark_border' }}
+
+
+ {{ $secondsToTimestamp(bookmark.time) }}
+
+
+ edit
+ delete
+
+
+
+
+
\ No newline at end of file
diff --git a/components/widgets/SpinnerIcon.vue b/components/widgets/SpinnerIcon.vue
new file mode 100644
index 00000000..60ad7d7e
--- /dev/null
+++ b/components/widgets/SpinnerIcon.vue
@@ -0,0 +1,235 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/layouts/default.vue b/layouts/default.vue
index f417fb1d..9114d512 100644
--- a/layouts/default.vue
+++ b/layouts/default.vue
@@ -96,7 +96,8 @@ export default {
},
currentUserAudiobookUpdate({ id, data }) {
if (data) {
- this.$localStore.updateUserAudiobookProgress(data)
+ console.log(`Current User Audiobook Updated ${id} ${JSON.stringify(data)}`)
+ this.$localStore.updateUserAudiobookData(data)
} else {
this.$localStore.removeAudiobookProgress(id)
}
@@ -413,6 +414,12 @@ export default {
console.log('Network status changed', status.connected, status.connectionType)
this.$store.commit('setNetworkStatus', status)
})
+ },
+ showErrorToast(message) {
+ this.$toast.error(message)
+ },
+ showSuccessToast(message) {
+ this.$toast.success(message)
}
},
mounted() {
@@ -423,6 +430,8 @@ export default {
this.$server.on('connectionFailed', this.socketConnectionFailed)
this.$server.on('initialStream', this.initialStream)
this.$server.on('currentUserAudiobookUpdate', this.currentUserAudiobookUpdate)
+ this.$server.on('show_error_toast', this.showErrorToast)
+ this.$server.on('show_success_toast', this.showSuccessToast)
if (this.$store.state.isFirstLoad) {
this.$store.commit('setIsFirstLoad', false)
@@ -458,6 +467,8 @@ export default {
this.$server.off('connected', this.connected)
this.$server.off('connectionFailed', this.socketConnectionFailed)
this.$server.off('initialStream', this.initialStream)
+ this.$server.off('show_error_toast', this.showErrorToast)
+ this.$server.off('show_success_toast', this.showSuccessToast)
}
}
diff --git a/package-lock.json b/package-lock.json
index 14ef8df8..3b96407b 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "audiobookshelf-app",
- "version": "v0.9.6-beta",
+ "version": "v0.9.17-beta",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -5151,6 +5151,11 @@
"type": "^1.0.1"
}
},
+ "date-fns": {
+ "version": "2.25.0",
+ "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.25.0.tgz",
+ "integrity": "sha512-ovYRFnTrbGPD4nqaEqescPEv1mNwvt+UTqI3Ay9SzNtey9NZnYu6E2qCcBBgJ6/2VF1zGGygpyTDITqpQQ5e+w=="
+ },
"de-indent": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz",
diff --git a/package.json b/package.json
index 61e8588a..b77a5cb4 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "audiobookshelf-app",
- "version": "v0.9.16-beta",
+ "version": "v0.9.17-beta",
"author": "advplyr",
"scripts": {
"dev": "nuxt --hostname localhost --port 1337",
@@ -23,6 +23,7 @@
"axios": "^0.21.1",
"capacitor-data-storage-sqlite": "^3.2.0",
"core-js": "^3.15.1",
+ "date-fns": "^2.25.0",
"epubjs": "^0.3.88",
"hls.js": "^1.0.9",
"libarchive.js": "^1.3.0",
@@ -36,4 +37,4 @@
"@nuxtjs/tailwindcss": "^4.2.0",
"postcss": "^8.3.5"
}
-}
\ No newline at end of file
+}
diff --git a/pages/audiobook/_id/index.vue b/pages/audiobook/_id/index.vue
index f0b1e6dc..170868b2 100644
--- a/pages/audiobook/_id/index.vue
+++ b/pages/audiobook/_id/index.vue
@@ -229,7 +229,7 @@ export default {
console.error('Progress reset failed', error)
})
}
- this.$localStore.updateUserAudiobookProgress({
+ this.$localStore.updateUserAudiobookData({
audiobookId: this.audiobookId,
currentTime: 0,
totalDuration: this.duration,
diff --git a/plugins/init.client.js b/plugins/init.client.js
index bc1d1808..6fd8d955 100644
--- a/plugins/init.client.js
+++ b/plugins/init.client.js
@@ -1,6 +1,17 @@
import Vue from 'vue'
+import { formatDistance, format } from 'date-fns'
+
Vue.prototype.$isDev = process.env.NODE_ENV !== 'production'
+Vue.prototype.$dateDistanceFromNow = (unixms) => {
+ if (!unixms) return ''
+ return formatDistance(unixms, Date.now(), { addSuffix: true })
+}
+Vue.prototype.$formatDate = (unixms, fnsFormat = 'MM/dd/yyyy HH:mm') => {
+ if (!unixms) return ''
+ return format(unixms, fnsFormat)
+}
+
Vue.prototype.$bytesPretty = (bytes, decimals = 2) => {
if (isNaN(bytes) || bytes === null) return 'Invalid Bytes'
if (bytes === 0) {
diff --git a/plugins/store.js b/plugins/store.js
index 08bd356f..74f22b71 100644
--- a/plugins/store.js
+++ b/plugins/store.js
@@ -458,15 +458,17 @@ class LocalStorage {
async setAllAudiobookProgress(progresses) {
this.userAudiobooks = progresses
await this.saveUserAudiobooks()
+
this.vuexStore.commit('user/setLocalUserAudiobooks', { ...this.userAudiobooks })
}
- async updateUserAudiobookProgress(progressPayload) {
+ async updateUserAudiobookData(progressPayload) {
this.userAudiobooks[progressPayload.audiobookId] = {
...progressPayload
}
- console.log('[LocalStorage] Updated User Audiobook Progress ' + progressPayload.audiobookId)
await this.saveUserAudiobooks()
+
+ this.vuexStore.commit('user/setUserAudiobooks', { ...this.userAudiobooks })
this.vuexStore.commit('user/setLocalUserAudiobooks', { ...this.userAudiobooks })
}
@@ -474,6 +476,8 @@ class LocalStorage {
if (!this.userAudiobooks[audiobookId]) return
delete this.userAudiobooks[audiobookId]
await this.saveUserAudiobooks()
+
+ this.vuexStore.commit('user/setUserAudiobooks', { ...this.userAudiobooks })
this.vuexStore.commit('user/setLocalUserAudiobooks', { ...this.userAudiobooks })
}
diff --git a/store/audiobooks.js b/store/audiobooks.js
index 2fda4aad..78df737e 100644
--- a/store/audiobooks.js
+++ b/store/audiobooks.js
@@ -53,7 +53,7 @@ export const getters = {
if (settings.mobileOrderBy === 'recent') {
return sort(filtered)[direction]((ab) => {
- var abprogress = rootGetters['user/getMostRecentAudiobookProgress'](ab.id)
+ var abprogress = rootGetters['user/getMostRecentUserAudiobookData'](ab.id)
if (!abprogress) return 0
return abprogress.lastUpdate
})
diff --git a/store/user.js b/store/user.js
index a4cc310f..2096522d 100644
--- a/store/user.js
+++ b/store/user.js
@@ -11,7 +11,8 @@ export const state = () => ({
playbackRate: 1,
bookshelfCoverSize: 120
},
- settingsListeners: []
+ settingsListeners: [],
+ userAudiobooksListeners: []
})
export const getters = {
@@ -23,9 +24,9 @@ export const getters = {
return state.user && state.user.audiobooks ? state.user.audiobooks[audiobookId] || null : null
},
getLocalUserAudiobook: (state) => (audiobookId) => {
- return state.user && state.user.localUserAudiobooks ? state.user.localUserAudiobooks[audiobookId] || null : null
+ return state.localUserAudiobooks ? state.localUserAudiobooks[audiobookId] || null : null
},
- getMostRecentAudiobookProgress: (state, getters) => (audiobookId) => {
+ getMostRecentUserAudiobookData: (state, getters) => (audiobookId) => {
var userAb = getters.getUserAudiobook(audiobookId)
var localUserAb = getters.getLocalUserAudiobook(audiobookId)
if (!localUserAb) return userAb
@@ -67,6 +68,15 @@ export const actions = {
export const mutations = {
setLocalUserAudiobooks(state, userAudiobooks) {
state.localUserAudiobooks = userAudiobooks
+ state.userAudiobooksListeners.forEach((listener) => {
+ listener.meth()
+ })
+ },
+ setUserAudiobooks(state, userAudiobooks) {
+ if (!state.user) return
+ state.user.audiobooks = {
+ ...userAudiobooks
+ }
},
setUser(state, user) {
state.user = user
@@ -102,5 +112,13 @@ export const mutations = {
},
removeSettingsListener(state, listenerId) {
state.settingsListeners = state.settingsListeners.filter(l => l.id !== listenerId)
+ },
+ addUserAudiobookListener(state, listener) {
+ var index = state.userAudiobooksListeners.findIndex(l => l.id === listener.id)
+ if (index >= 0) state.userAudiobooksListeners.splice(index, 1, listener)
+ else state.userAudiobooksListeners.push(listener)
+ },
+ removeUserAudiobookListener(state, listenerId) {
+ state.userAudiobooksListeners = state.userAudiobooksListeners.filter(l => l.id !== listenerId)
}
}
\ No newline at end of file