add
Create Bookmark
@@ -61,6 +54,7 @@ export default {
},
data() {
return {
+ selectedBookmark: null,
showBookmarkTitleInput: false,
newBookmarkTitle: ''
}
@@ -81,22 +75,45 @@ export default {
set(val) {
this.$emit('input', val)
}
+ },
+ canCreateBookmark() {
+ return !this.bookmarks.find((bm) => bm.time === this.currentTime)
}
},
methods: {
+ editBookmark(bm) {
+ this.selectedBookmark = bm
+ this.newBookmarkTitle = bm.title
+ this.showBookmarkTitleInput = true
+ },
+ deleteBookmark(bm) {
+ var bookmark = { ...bm, audiobookId: this.audiobookId }
+ this.$emit('delete', bookmark)
+ },
clickBookmark(bm) {
this.$emit('select', bm)
},
createBookmark() {
+ this.selectedBookmark = null
+ this.newBookmarkTitle = this.$formatDate(Date.now(), 'MMM dd, yyyy HH:mm')
this.showBookmarkTitleInput = true
},
submitBookmark() {
- var bookmark = {
- audiobookId: this.audiobookId,
- title: this.newBookmarkTitle,
- time: this.currentTime
+ if (this.selectedBookmark) {
+ if (this.selectedBookmark.title !== this.newBookmarkTitle) {
+ var bookmark = { ...this.selectedBookmark }
+ bookmark.audiobookId = this.audiobookId
+ bookmark.title = this.newBookmarkTitle
+ this.$emit('update', bookmark)
+ }
+ } else {
+ var bookmark = {
+ audiobookId: this.audiobookId,
+ title: this.newBookmarkTitle,
+ time: this.currentTime
+ }
+ this.$emit('create', bookmark)
}
- this.$emit('create', bookmark)
this.newBookmarkTitle = ''
this.showBookmarkTitleInput = false
}
diff --git a/client/components/modals/bookmarks/BookmarkItem.vue b/client/components/modals/bookmarks/BookmarkItem.vue
new file mode 100644
index 00000000..032ed7f7
--- /dev/null
+++ b/client/components/modals/bookmarks/BookmarkItem.vue
@@ -0,0 +1,45 @@
+
+
+
{{ highlight ? 'bookmark' : 'bookmark_border' }}
+
+
+ {{ $secondsToTimestamp(bookmark.time) }}
+
+
+ edit
+ delete
+
+
+
+
+
\ No newline at end of file
diff --git a/client/layouts/default.vue b/client/layouts/default.vue
index 15f30ffa..3d1ebddb 100644
--- a/client/layouts/default.vue
+++ b/client/layouts/default.vue
@@ -239,6 +239,12 @@ export default {
download.status = this.$constants.DownloadStatus.EXPIRED
this.$store.commit('downloads/addUpdateDownload', download)
},
+ showErrorToast(message) {
+ this.$toast.error(message)
+ },
+ showSuccessToast(message) {
+ this.$toast.success(message)
+ },
logEvtReceived(payload) {
this.$store.commit('logs/logEvt', payload)
},
@@ -303,6 +309,10 @@ export default {
this.socket.on('download_killed', this.downloadKilled)
this.socket.on('download_expired', this.downloadExpired)
+ // Toast Listeners
+ this.socket.on('show_error_toast', this.showErrorToast)
+ this.socket.on('show_success_toast', this.showSuccessToast)
+
this.socket.on('log', this.logEvtReceived)
this.socket.on('backup_applied', this.backupApplied)
diff --git a/server/Server.js b/server/Server.js
index 59518e55..b983f0b3 100644
--- a/server/Server.js
+++ b/server/Server.js
@@ -11,6 +11,7 @@ const { version } = require('../package.json')
// Utils
const { ScanResult } = require('./utils/constants')
const filePerms = require('./utils/filePerms')
+const { secondsToTimestamp } = require('./utils/fileUtils')
const Logger = require('./Logger')
// Classes
@@ -261,6 +262,8 @@ class Server {
// Bookmarks
socket.on('create_bookmark', (payload) => this.createBookmark(socket, payload))
+ socket.on('update_bookmark', (payload) => this.updateBookmark(socket, payload))
+ socket.on('delete_bookmark', (payload) => this.deleteBookmark(socket, payload))
socket.on('test', () => {
socket.emit('test_received', socket.id)
@@ -481,15 +484,66 @@ class Server {
return
}
var userAudiobook = client.user.createBookmark(payload)
- if (userAudiobook) {
- await this.db.updateEntity('user', client.user)
-
- this.clientEmitter(client.user.id, 'bookmark_created', payload.time)
- this.clientEmitter(client.user.id, 'current_user_audiobook_update', {
- id: userAudiobook.audiobookId,
- data: userAudiobook || null
- })
+ if (!userAudiobook || userAudiobook.error) {
+ var failMessage = (userAudiobook ? userAudiobook.error : null) || 'Unknown Error'
+ socket.emit('show_error_toast', `Failed to create Bookmark: ${failMessage}`)
+ return
}
+
+ await this.db.updateEntity('user', client.user)
+
+ socket.emit('show_success_toast', `${secondsToTimestamp(payload.time)} Bookmarked`)
+
+ this.clientEmitter(client.user.id, 'current_user_audiobook_update', {
+ id: userAudiobook.audiobookId,
+ data: userAudiobook || null
+ })
+ }
+
+ async updateBookmark(socket, payload) {
+ var client = socket.sheepClient
+ if (!client || !client.user) {
+ Logger.error('[Server] updateBookmark invalid socket client')
+ return
+ }
+ var userAudiobook = client.user.updateBookmark(payload)
+ if (!userAudiobook || userAudiobook.error) {
+ var failMessage = (userAudiobook ? userAudiobook.error : null) || 'Unknown Error'
+ socket.emit('show_error_toast', `Failed to update Bookmark: ${failMessage}`)
+ return
+ }
+
+ await this.db.updateEntity('user', client.user)
+
+ socket.emit('show_success_toast', `Bookmark ${secondsToTimestamp(payload.time)} Updated`)
+
+ this.clientEmitter(client.user.id, 'current_user_audiobook_update', {
+ id: userAudiobook.audiobookId,
+ data: userAudiobook || null
+ })
+ }
+
+ async deleteBookmark(socket, payload) {
+ var client = socket.sheepClient
+ if (!client || !client.user) {
+ Logger.error('[Server] deleteBookmark invalid socket client')
+ return
+ }
+ var userAudiobook = client.user.deleteBookmark(payload)
+ if (!userAudiobook || userAudiobook.error) {
+ var failMessage = (userAudiobook ? userAudiobook.error : null) || 'Unknown Error'
+ socket.emit('show_error_toast', `Failed to delete Bookmark: ${failMessage}`)
+ return
+ }
+
+ await this.db.updateEntity('user', client.user)
+
+ socket.emit('show_success_toast', `Bookmark ${secondsToTimestamp(payload.time)} Removed`)
+
+ this.clientEmitter(client.user.id, 'current_user_audiobook_update', {
+ id: userAudiobook.audiobookId,
+ data: userAudiobook || null
+ })
}
async authenticateSocket(socket, token) {
diff --git a/server/objects/AudiobookProgress.js b/server/objects/AudiobookProgress.js
index 23f24814..a9ed85f0 100644
--- a/server/objects/AudiobookProgress.js
+++ b/server/objects/AudiobookProgress.js
@@ -107,11 +107,26 @@ class AudiobookProgress {
return hasUpdates
}
+ checkBookmarkExists(time) {
+ return this.bookmarks.find(bm => bm.time === time)
+ }
+
createBookmark(time, title) {
var newBookmark = new AudioBookmark()
newBookmark.setData(time, title)
this.bookmarks.push(newBookmark)
return newBookmark
}
+
+ updateBookmark(time, title) {
+ var bookmark = this.bookmarks.find(bm => bm.time === time)
+ if (!bookmark) return false
+ bookmark.title = title
+ return bookmark
+ }
+
+ deleteBookmark(time) {
+ this.bookmarks = this.bookmarks.filter(bm => bm.time !== time)
+ }
}
module.exports = AudiobookProgress
\ No newline at end of file
diff --git a/server/objects/User.js b/server/objects/User.js
index 0e8b459d..deb56d4a 100644
--- a/server/objects/User.js
+++ b/server/objects/User.js
@@ -281,11 +281,52 @@ class User {
createBookmark({ audiobookId, time, title }) {
if (!this.audiobooks || !this.audiobooks[audiobookId]) {
- return false
+ return {
+ error: 'Invalid Audiobook'
+ }
}
+ if (this.audiobooks[audiobookId].checkBookmarkExists(time)) {
+ return {
+ error: 'Bookmark already exists'
+ }
+ }
+
var success = this.audiobooks[audiobookId].createBookmark(time, title)
if (success) return this.audiobooks[audiobookId]
return null
}
+
+ updateBookmark({ audiobookId, time, title }) {
+ if (!this.audiobooks || !this.audiobooks[audiobookId]) {
+ return {
+ error: 'Invalid Audiobook'
+ }
+ }
+ if (!this.audiobooks[audiobookId].checkBookmarkExists(time)) {
+ return {
+ error: 'Bookmark does not exist'
+ }
+ }
+
+ var success = this.audiobooks[audiobookId].updateBookmark(time, title)
+ if (success) return this.audiobooks[audiobookId]
+ return null
+ }
+
+ deleteBookmark({ audiobookId, time }) {
+ if (!this.audiobooks || !this.audiobooks[audiobookId]) {
+ return {
+ error: 'Invalid Audiobook'
+ }
+ }
+ if (!this.audiobooks[audiobookId].checkBookmarkExists(time)) {
+ return {
+ error: 'Bookmark does not exist'
+ }
+ }
+
+ this.audiobooks[audiobookId].deleteBookmark(time)
+ return this.audiobooks[audiobookId]
+ }
}
module.exports = User
\ No newline at end of file
diff --git a/server/utils/fileUtils.js b/server/utils/fileUtils.js
index 4d4750d7..098c4992 100644
--- a/server/utils/fileUtils.js
+++ b/server/utils/fileUtils.js
@@ -69,7 +69,7 @@ function secondsToTimestamp(seconds) {
_seconds -= _minutes * 60
var _hours = Math.floor(_minutes / 60)
_minutes -= _hours * 60
- _seconds = Math.round(_seconds)
+ _seconds = Math.floor(_seconds)
if (!_hours) {
return `${_minutes}:${_seconds.toString().padStart(2, '0')}`
}