mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2025-08-04 10:14:36 +02:00
New data model play media entity, PlaybackSessionManager
This commit is contained in:
parent
1cf9e85272
commit
099ae7c776
54 changed files with 841 additions and 902 deletions
|
@ -175,8 +175,8 @@ export default {
|
|||
})
|
||||
},
|
||||
batchDeleteClick() {
|
||||
var audiobookText = this.numLibraryItemsSelected > 1 ? `these ${this.numLibraryItemsSelected} audiobooks` : 'this audiobook'
|
||||
var confirmMsg = `Are you sure you want to remove ${audiobookText}?\n\n*Does not delete your files, only removes the audiobooks from AudioBookshelf`
|
||||
var audiobookText = this.numLibraryItemsSelected > 1 ? `these ${this.numLibraryItemsSelected} items` : 'this item'
|
||||
var confirmMsg = `Are you sure you want to remove ${audiobookText}?\n\n*Does not delete your files, only removes the items from Audiobookshelf`
|
||||
if (confirm(confirmMsg)) {
|
||||
this.processingBatchDelete = true
|
||||
this.$store.commit('setProcessingBatch', true)
|
||||
|
|
|
@ -300,11 +300,11 @@ export default {
|
|||
var firstBookPage = Math.floor(firstBookIndex / this.booksPerFetch)
|
||||
var lastBookPage = Math.floor(lastBookIndex / this.booksPerFetch)
|
||||
if (!this.pagesLoaded[firstBookPage]) {
|
||||
console.log('Must load next batch', firstBookPage, 'book index', firstBookIndex)
|
||||
// console.log('Must load next batch', firstBookPage, 'book index', firstBookIndex)
|
||||
this.loadPage(firstBookPage)
|
||||
}
|
||||
if (!this.pagesLoaded[lastBookPage]) {
|
||||
console.log('Must load last next batch', lastBookPage, 'book index', lastBookIndex)
|
||||
// console.log('Must load last next batch', lastBookPage, 'book index', lastBookIndex)
|
||||
this.loadPage(lastBookPage)
|
||||
}
|
||||
|
||||
|
|
|
@ -95,16 +95,17 @@ export default {
|
|||
user() {
|
||||
return this.$store.state.user.user
|
||||
},
|
||||
userAudiobook() {
|
||||
userLibraryItemProgress() {
|
||||
if (!this.libraryItemId) return
|
||||
return this.$store.getters['user/getUserLibraryItemProgress'](this.libraryItemId)
|
||||
},
|
||||
userAudiobookCurrentTime() {
|
||||
return this.userAudiobook ? this.userAudiobook.currentTime || 0 : 0
|
||||
userItemCurrentTime() {
|
||||
return this.userLibraryItemProgress ? this.userLibraryItemProgress.currentTime || 0 : 0
|
||||
},
|
||||
bookmarks() {
|
||||
if (!this.userAudiobook) return []
|
||||
return (this.userAudiobook.bookmarks || []).map((bm) => ({ ...bm })).sort((a, b) => a.time - b.time)
|
||||
return []
|
||||
// if (!this.userAudiobook) return []
|
||||
// return (this.userAudiobook.bookmarks || []).map((bm) => ({ ...bm })).sort((a, b) => a.time - b.time)
|
||||
},
|
||||
streamLibraryItem() {
|
||||
return this.$store.state.streamLibraryItem
|
||||
|
@ -236,9 +237,9 @@ export default {
|
|||
console.error('No Audio Ref')
|
||||
}
|
||||
},
|
||||
streamOpen(stream) {
|
||||
this.$store.commit('setLibraryItemStream', stream.libraryItem)
|
||||
this.playerHandler.prepareStream(stream)
|
||||
sessionOpen(session) {
|
||||
this.$store.commit('setLibraryItemStream', session.libraryItem)
|
||||
this.playerHandler.prepareOpenSession(session)
|
||||
},
|
||||
streamClosed(streamId) {
|
||||
// Stream was closed from the server
|
||||
|
@ -282,7 +283,7 @@ export default {
|
|||
if (!libraryItem) return
|
||||
this.$store.commit('setLibraryItemStream', libraryItem)
|
||||
|
||||
this.playerHandler.load(libraryItem, true, this.userAudiobookCurrentTime)
|
||||
this.playerHandler.load(libraryItem, true)
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
|
|
|
@ -161,10 +161,12 @@ export default {
|
|||
return this._libraryItem.libraryId
|
||||
},
|
||||
hasEbook() {
|
||||
return this.media.numEbooks
|
||||
if (!this.media.ebooks) return 0
|
||||
return this.media.ebooks.length
|
||||
},
|
||||
hasTracks() {
|
||||
return this.media.numTracks
|
||||
hasAudiobook() {
|
||||
if (!this.media.audiobooks) return 0
|
||||
return this.media.audiobooks.length
|
||||
},
|
||||
processingBatch() {
|
||||
return this.store.state.processingBatch
|
||||
|
@ -244,7 +246,7 @@ export default {
|
|||
return !this.isSelectionMode && this.showExperimentalFeatures && !this.showPlayButton && this.hasEbook
|
||||
},
|
||||
showPlayButton() {
|
||||
return !this.isSelectionMode && !this.isMissing && !this.isInvalid && this.hasTracks && !this.isStreaming
|
||||
return !this.isSelectionMode && !this.isMissing && !this.isInvalid && this.hasAudiobook && !this.isStreaming
|
||||
},
|
||||
showSmallEBookIcon() {
|
||||
return !this.isSelectionMode && this.showExperimentalFeatures && this.hasEbook
|
||||
|
@ -310,7 +312,7 @@ export default {
|
|||
}
|
||||
]
|
||||
if (this.userCanUpdate) {
|
||||
if (this.hasTracks) {
|
||||
if (this.hasAudiobook) {
|
||||
items.push({
|
||||
func: 'showEditModalTracks',
|
||||
text: 'Tracks'
|
||||
|
|
|
@ -175,7 +175,7 @@ export default {
|
|||
return this.filterData.languages || []
|
||||
},
|
||||
progress() {
|
||||
return ['Read', 'Unread', 'In Progress']
|
||||
return ['Finished', 'In Progress', 'Not Started']
|
||||
},
|
||||
sublistItems() {
|
||||
return (this[this.sublist] || []).map((item) => {
|
||||
|
|
|
@ -168,7 +168,6 @@ export default {
|
|||
},
|
||||
async updateDetails(updatedDetails) {
|
||||
this.isProcessing = true
|
||||
console.log('Sending update', updatedDetails.updatePayload)
|
||||
var updateResult = await this.$axios.$patch(`/api/items/${this.libraryItemId}/media`, updatedDetails.updatePayload).catch((error) => {
|
||||
console.error('Failed to update', error)
|
||||
return false
|
||||
|
|
|
@ -64,7 +64,6 @@ export default {
|
|||
computed: {
|
||||
_directories() {
|
||||
return this.directories.map((d) => {
|
||||
console.log('Directories', d)
|
||||
var isUsed = !!this.paths.find((path) => path.endsWith(d.path))
|
||||
var isSelected = d.path === this.selectedPath
|
||||
var classes = []
|
||||
|
|
|
@ -1,105 +0,0 @@
|
|||
<template>
|
||||
<div class="w-full my-2">
|
||||
<div class="w-full bg-primary px-4 py-2 flex items-center cursor-pointer">
|
||||
<p class="pr-4">All Files</p>
|
||||
<span class="bg-black-400 rounded-xl py-1 px-2 text-sm font-mono">{{ allFiles.length }}</span>
|
||||
<div class="flex-grow" />
|
||||
|
||||
<ui-btn small :color="showFullPath ? 'gray-600' : 'primary'" @click.stop="showFullPath = !showFullPath">Full Path</ui-btn>
|
||||
</div>
|
||||
<div class="w-full">
|
||||
<table class="text-sm tracksTable">
|
||||
<tr class="font-book">
|
||||
<th class="text-left px-4">Path</th>
|
||||
<th class="text-left px-4 w-24">Filetype</th>
|
||||
<th v-if="userCanDownload" class="text-center w-20">Download</th>
|
||||
</tr>
|
||||
<template v-for="file in allFiles">
|
||||
<tr :key="file.path">
|
||||
<td class="font-book pl-2">
|
||||
{{ showFullPath ? file.fullPath : file.path }}
|
||||
</td>
|
||||
<td class="text-xs">
|
||||
<p>{{ file.filetype }}</p>
|
||||
</td>
|
||||
<td v-if="userCanDownload" class="text-center">
|
||||
<a :href="`/s/book/${audiobookId}/${file.relativePath}?token=${userToken}`" download><span class="material-icons icon-text">download</span></a>
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
audiobook: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
showFullPath: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
audiobookId() {
|
||||
return this.audiobook.id
|
||||
},
|
||||
audiobookPath() {
|
||||
return this.audiobook.path
|
||||
},
|
||||
userCanDownload() {
|
||||
return this.$store.getters['user/getUserCanDownload']
|
||||
},
|
||||
userToken() {
|
||||
return this.$store.getters['user/getToken']
|
||||
},
|
||||
isMissing() {
|
||||
return this.audiobook.isMissing
|
||||
},
|
||||
showDownload() {
|
||||
return this.userCanDownload && !this.isMissing
|
||||
},
|
||||
otherFiles() {
|
||||
return this.audiobook.otherFiles || []
|
||||
},
|
||||
audioFiles() {
|
||||
return this.audiobook.audioFiles || []
|
||||
},
|
||||
audioFilesCleaned() {
|
||||
return this.audioFiles.map((af) => {
|
||||
return {
|
||||
path: af.path,
|
||||
fullPath: af.fullPath,
|
||||
relativePath: this.getRelativePath(af.path),
|
||||
filetype: 'audio'
|
||||
}
|
||||
})
|
||||
},
|
||||
otherFilesCleaned() {
|
||||
return this.otherFiles.map((af) => {
|
||||
return {
|
||||
path: af.path,
|
||||
fullPath: af.fullPath,
|
||||
relativePath: this.getRelativePath(af.path),
|
||||
filetype: af.filetype
|
||||
}
|
||||
})
|
||||
},
|
||||
allFiles() {
|
||||
return this.audioFilesCleaned.concat(this.otherFilesCleaned)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getRelativePath(path) {
|
||||
var relativePath = path.replace(/\\/g, '/').replace(this.audiobookPath.replace(/\\/g, '/') + '/', '')
|
||||
return this.$encodeUriPath(relativePath)
|
||||
}
|
||||
},
|
||||
mounted() {}
|
||||
}
|
||||
</script>
|
|
@ -26,11 +26,11 @@
|
|||
</td>
|
||||
<td class="text-sm">{{ user.type }}</td>
|
||||
<td class="hidden lg:table-cell">
|
||||
<div v-if="usersOnline[user.id] && usersOnline[user.id].stream && usersOnline[user.id].stream.libraryItem && usersOnline[user.id].stream.libraryItem.media">
|
||||
<p class="truncate text-xs">Reading: {{ usersOnline[user.id].stream.libraryItem.media.metadata.title || '' }}</p>
|
||||
<div v-if="usersOnline[user.id] && usersOnline[user.id].session && usersOnline[user.id].session.libraryItem && usersOnline[user.id].session.libraryItem.media">
|
||||
<p class="truncate text-xs">Listening: {{ usersOnline[user.id].session.libraryItem.media.metadata.title || '' }}</p>
|
||||
</div>
|
||||
<div v-else-if="user.audiobooks && getLastRead(user.audiobooks)">
|
||||
<p class="truncate text-xs">Last: {{ getLastRead(user.audiobooks) }}</p>
|
||||
<div v-else-if="user.mostRecent">
|
||||
<p class="truncate text-xs">Last: {{ user.mostRecent.metadata.title }}</p>
|
||||
</div>
|
||||
</td>
|
||||
<td class="text-xs font-mono hidden sm:table-cell">
|
||||
|
@ -78,23 +78,11 @@ export default {
|
|||
},
|
||||
usersOnline() {
|
||||
var usermap = {}
|
||||
this.$store.state.users.users.forEach((u) => (usermap[u.id] = { online: true, stream: u.stream }))
|
||||
this.$store.state.users.users.forEach((u) => (usermap[u.id] = { online: true, session: u.session }))
|
||||
return usermap
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getLastRead(audiobooks) {
|
||||
var abs = Object.values(audiobooks).filter((ab) => {
|
||||
return ab.progress > 0
|
||||
})
|
||||
if (abs.length) {
|
||||
abs = abs.sort((a, b) => b.lastUpdate - a.lastUpdate)
|
||||
// Book object is attached on request
|
||||
if (abs[0].book) return abs[0].book.title
|
||||
return abs[0].audiobookTitle ? abs[0].audiobookTitle : null
|
||||
}
|
||||
return null
|
||||
},
|
||||
deleteUserClick(user) {
|
||||
if (this.isDeletingUser) return
|
||||
if (confirm(`Are you sure you want to permanently delete user "${user.username}"?`)) {
|
||||
|
|
|
@ -33,7 +33,6 @@ export default {
|
|||
var _files = Array.from(e.target.files)
|
||||
if (_files && _files.length) {
|
||||
var file = _files[0]
|
||||
console.log('File', file)
|
||||
this.$emit('change', file)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -78,7 +78,7 @@ export default {
|
|||
console.error('Failed to get search results', error)
|
||||
return []
|
||||
})
|
||||
console.log('Search results', results)
|
||||
// console.log('Search results', results)
|
||||
this.items = results || []
|
||||
this.searching = false
|
||||
},
|
||||
|
|
|
@ -276,7 +276,7 @@ export default {
|
|||
if (!matchingItem) return false
|
||||
for (var key in item) {
|
||||
if (item[key] !== matchingItem[key]) {
|
||||
console.log('Object array item keys changed', key, item[key], matchingItem[key])
|
||||
// console.log('Object array item keys changed', key, item[key], matchingItem[key])
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue