mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2026-06-04 18:00:45 +02:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| aebb3ff413 | |||
| a58d486c44 | |||
| 4a76ba0226 | |||
| 7afff57b5e | |||
| 2e13c5bd50 | |||
| 344de941ff | |||
| 5c0cd98cb3 | |||
| 8974c582fc |
@@ -19,6 +19,14 @@
|
|||||||
</div>
|
</div>
|
||||||
<div v-else-if="!totalShelves && initialized" class="w-full py-16">
|
<div v-else-if="!totalShelves && initialized" class="w-full py-16">
|
||||||
<p class="text-xl text-center">{{ emptyMessage }}</p>
|
<p class="text-xl text-center">{{ emptyMessage }}</p>
|
||||||
|
<div v-if="entityName === 'collections' || entityName === 'playlists'" class="flex justify-center mt-4">
|
||||||
|
{{ emptyMessageHelp }}
|
||||||
|
<ui-tooltip :text="$strings.LabelClickForMoreInfo" class="inline-flex ml-2">
|
||||||
|
<a href="https://www.audiobookshelf.org/guides/collections" target="_blank" class="inline-flex">
|
||||||
|
<span class="material-symbols text-xl w-5 text-gray-200">help_outline</span>
|
||||||
|
</a>
|
||||||
|
</ui-tooltip>
|
||||||
|
</div>
|
||||||
<!-- Clear filter only available on Library bookshelf -->
|
<!-- Clear filter only available on Library bookshelf -->
|
||||||
<div v-if="entityName === 'items'" class="flex justify-center mt-2">
|
<div v-if="entityName === 'items'" class="flex justify-center mt-2">
|
||||||
<ui-btn v-if="hasFilter" color="primary" @click="clearFilter">{{ $strings.ButtonClearFilter }}</ui-btn>
|
<ui-btn v-if="hasFilter" color="primary" @click="clearFilter">{{ $strings.ButtonClearFilter }}</ui-btn>
|
||||||
@@ -109,6 +117,11 @@ export default {
|
|||||||
}
|
}
|
||||||
return this.$strings.MessageNoResults
|
return this.$strings.MessageNoResults
|
||||||
},
|
},
|
||||||
|
emptyMessageHelp() {
|
||||||
|
if (this.page === 'collections') return this.$strings.MessageBookshelfNoCollectionsHelp
|
||||||
|
if (this.page === 'playlists') return this.$strings.MessageNoUserPlaylistsHelp
|
||||||
|
return ''
|
||||||
|
},
|
||||||
entityName() {
|
entityName() {
|
||||||
if (!this.page) return 'items'
|
if (!this.page) return 'items'
|
||||||
return this.page
|
return this.page
|
||||||
|
|||||||
@@ -31,13 +31,6 @@
|
|||||||
<p cy-id="placeholderAuthorText" aria-hidden="true" class="text-center" style="color: rgb(247 223 187); opacity: 0.75" :style="{ fontSize: authorFontSize + 'em' }">{{ authorCleaned }}</p>
|
<p cy-id="placeholderAuthorText" aria-hidden="true" class="text-center" style="color: rgb(247 223 187); opacity: 0.75" :style="{ fontSize: authorFontSize + 'em' }">{{ authorCleaned }}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="seriesSequenceList" class="absolute rounded-lg bg-black bg-opacity-90 box-shadow-md z-20 text-right" :style="{ top: 0.375 + 'em', right: 0.375 + 'em', padding: `${0.1}em ${0.25}em` }" style="background-color: #78350f">
|
|
||||||
<p :style="{ fontSize: 0.8 + 'em' }">#{{ seriesSequenceList }}</p>
|
|
||||||
</div>
|
|
||||||
<div v-else-if="booksInSeries" class="absolute rounded-lg bg-black bg-opacity-90 box-shadow-md z-20" :style="{ top: 0.375 + 'em', right: 0.375 + 'em', padding: `${0.1}em ${0.25}em` }" style="background-color: #cd9d49dd">
|
|
||||||
<p :style="{ fontSize: 0.8 + 'em' }">{{ booksInSeries }}</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- No progress shown for podcasts (unless showing podcast episode) -->
|
<!-- No progress shown for podcasts (unless showing podcast episode) -->
|
||||||
<div cy-id="progressBar" v-if="!isPodcast || episodeProgress" class="absolute bottom-0 left-0 h-1e max-w-full z-20 rounded-b box-shadow-progressbar" :class="itemIsFinished ? 'bg-success' : 'bg-yellow-400'" :style="{ width: coverWidth * userProgressPercent + 'px' }"></div>
|
<div cy-id="progressBar" v-if="!isPodcast || episodeProgress" class="absolute bottom-0 left-0 h-1e max-w-full z-20 rounded-b box-shadow-progressbar" :class="itemIsFinished ? 'bg-success' : 'bg-yellow-400'" :style="{ width: coverWidth * userProgressPercent + 'px' }"></div>
|
||||||
|
|
||||||
@@ -244,6 +237,7 @@ export default {
|
|||||||
return this.mediaMetadata.series
|
return this.mediaMetadata.series
|
||||||
},
|
},
|
||||||
seriesName() {
|
seriesName() {
|
||||||
|
if (this.collapsedSeries?.name) return this.collapsedSeries.name
|
||||||
return this.series?.name || null
|
return this.series?.name || null
|
||||||
},
|
},
|
||||||
seriesSequence() {
|
seriesSequence() {
|
||||||
|
|||||||
@@ -19,9 +19,20 @@
|
|||||||
</template>
|
</template>
|
||||||
</transition-group>
|
</transition-group>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="!collections.length" class="flex h-32 items-center justify-center">
|
<div v-if="!collections.length" class="flex h-32 items-center justify-center text-center px-2">
|
||||||
<p class="text-xl">{{ $strings.MessageNoCollections }}</p>
|
<div>
|
||||||
|
<p class="text-xl mb-2">{{ $strings.MessageNoCollections }}</p>
|
||||||
|
<div class="text-sm flex items-center justify-center text-gray-200">
|
||||||
|
<p>{{ $strings.MessageBookshelfNoCollectionsHelp }}</p>
|
||||||
|
<ui-tooltip :text="$strings.LabelClickForMoreInfo" class="inline-flex ml-2">
|
||||||
|
<a href="https://www.audiobookshelf.org/guides/collections" target="_blank" class="inline-flex">
|
||||||
|
<span class="material-symbols text-xl w-5 text-gray-200">help_outline</span>
|
||||||
|
</a>
|
||||||
|
</ui-tooltip>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="w-full h-px bg-white bg-opacity-10" />
|
<div class="w-full h-px bg-white bg-opacity-10" />
|
||||||
<form @submit.prevent="submitCreateCollection">
|
<form @submit.prevent="submitCreateCollection">
|
||||||
<div class="flex px-4 py-2 items-center text-center border-b border-white border-opacity-10 text-white text-opacity-80">
|
<div class="flex px-4 py-2 items-center text-center border-b border-white border-opacity-10 text-white text-opacity-80">
|
||||||
|
|||||||
@@ -19,8 +19,18 @@
|
|||||||
</template>
|
</template>
|
||||||
</transition-group>
|
</transition-group>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="!playlists.length" class="flex h-32 items-center justify-center">
|
<div v-if="!playlists.length" class="flex h-32 items-center justify-center text-center px-2">
|
||||||
<p class="text-xl">{{ $strings.MessageNoUserPlaylists }}</p>
|
<div>
|
||||||
|
<p class="text-xl mb-2">{{ $strings.MessageNoUserPlaylists }}</p>
|
||||||
|
<div class="text-sm flex items-center justify-center text-gray-200">
|
||||||
|
<p>{{ $strings.MessageNoUserPlaylistsHelp }}</p>
|
||||||
|
<ui-tooltip :text="$strings.LabelClickForMoreInfo" class="inline-flex ml-2">
|
||||||
|
<a href="https://www.audiobookshelf.org/guides/collections" target="_blank" class="inline-flex">
|
||||||
|
<span class="material-symbols text-xl w-5 text-gray-200">help_outline</span>
|
||||||
|
</a>
|
||||||
|
</ui-tooltip>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-full h-px bg-white bg-opacity-10" />
|
<div class="w-full h-px bg-white bg-opacity-10" />
|
||||||
<form @submit.prevent="submitCreatePlaylist">
|
<form @submit.prevent="submitCreatePlaylist">
|
||||||
|
|||||||
@@ -414,11 +414,8 @@ export default {
|
|||||||
|
|
||||||
const audioEl = this.audioEl || document.createElement('audio')
|
const audioEl = this.audioEl || document.createElement('audio')
|
||||||
var src = audioTrack.contentUrl + `?token=${this.userToken}`
|
var src = audioTrack.contentUrl + `?token=${this.userToken}`
|
||||||
if (this.$isDev) {
|
|
||||||
src = `${process.env.serverUrl}${src}`
|
|
||||||
}
|
|
||||||
|
|
||||||
audioEl.src = src
|
audioEl.src = `${process.env.serverUrl}${src}`
|
||||||
audioEl.id = 'chapter-audio'
|
audioEl.id = 'chapter-audio'
|
||||||
document.body.appendChild(audioEl)
|
document.body.appendChild(audioEl)
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
export default class AudioTrack {
|
export default class AudioTrack {
|
||||||
constructor(track, userToken) {
|
constructor(track, userToken, routerBasePath) {
|
||||||
this.index = track.index || 0
|
this.index = track.index || 0
|
||||||
this.startOffset = track.startOffset || 0 // Total time of all previous tracks
|
this.startOffset = track.startOffset || 0 // Total time of all previous tracks
|
||||||
this.duration = track.duration || 0
|
this.duration = track.duration || 0
|
||||||
@@ -9,20 +9,27 @@ export default class AudioTrack {
|
|||||||
this.metadata = track.metadata || {}
|
this.metadata = track.metadata || {}
|
||||||
|
|
||||||
this.userToken = userToken
|
this.userToken = userToken
|
||||||
|
this.routerBasePath = routerBasePath || ''
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used for CastPlayer
|
||||||
|
*/
|
||||||
get fullContentUrl() {
|
get fullContentUrl() {
|
||||||
if (!this.contentUrl || this.contentUrl.startsWith('http')) return this.contentUrl
|
if (!this.contentUrl || this.contentUrl.startsWith('http')) return this.contentUrl
|
||||||
|
|
||||||
if (process.env.NODE_ENV === 'development') {
|
if (process.env.NODE_ENV === 'development') {
|
||||||
return `${process.env.serverUrl}${this.contentUrl}?token=${this.userToken}`
|
return `${process.env.serverUrl}${this.contentUrl}?token=${this.userToken}`
|
||||||
}
|
}
|
||||||
return `${window.location.origin}${this.contentUrl}?token=${this.userToken}`
|
return `${window.location.origin}${this.routerBasePath}${this.contentUrl}?token=${this.userToken}`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used for LocalPlayer
|
||||||
|
*/
|
||||||
get relativeContentUrl() {
|
get relativeContentUrl() {
|
||||||
if (!this.contentUrl || this.contentUrl.startsWith('http')) return this.contentUrl
|
if (!this.contentUrl || this.contentUrl.startsWith('http')) return this.contentUrl
|
||||||
|
|
||||||
return this.contentUrl + `?token=${this.userToken}`
|
return `${this.routerBasePath}${this.contentUrl}?token=${this.userToken}`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -226,7 +226,7 @@ export default class PlayerHandler {
|
|||||||
|
|
||||||
console.log('[PlayerHandler] Preparing Session', session)
|
console.log('[PlayerHandler] Preparing Session', session)
|
||||||
|
|
||||||
var audioTracks = session.audioTracks.map((at) => new AudioTrack(at, this.userToken))
|
var audioTracks = session.audioTracks.map((at) => new AudioTrack(at, this.userToken, this.ctx.$config.routerBasePath))
|
||||||
|
|
||||||
this.ctx.playerLoading = true
|
this.ctx.playerLoading = true
|
||||||
this.isHlsTranscode = true
|
this.isHlsTranscode = true
|
||||||
|
|||||||
@@ -711,6 +711,7 @@
|
|||||||
"MessageBatchEditPopulateMapDetailsItemHelp": "Populate enabled map details fields with data from this item",
|
"MessageBatchEditPopulateMapDetailsItemHelp": "Populate enabled map details fields with data from this item",
|
||||||
"MessageBatchQuickMatchDescription": "Quick Match will attempt to add missing covers and metadata for the selected items. Enable the options below to allow Quick Match to overwrite existing covers and/or metadata.",
|
"MessageBatchQuickMatchDescription": "Quick Match will attempt to add missing covers and metadata for the selected items. Enable the options below to allow Quick Match to overwrite existing covers and/or metadata.",
|
||||||
"MessageBookshelfNoCollections": "You haven't made any collections yet",
|
"MessageBookshelfNoCollections": "You haven't made any collections yet",
|
||||||
|
"MessageBookshelfNoCollectionsHelp": "Collections are public. All users with access to the library can see them.",
|
||||||
"MessageBookshelfNoRSSFeeds": "No RSS feeds are open",
|
"MessageBookshelfNoRSSFeeds": "No RSS feeds are open",
|
||||||
"MessageBookshelfNoResultsForFilter": "No results for filter \"{0}: {1}\"",
|
"MessageBookshelfNoResultsForFilter": "No results for filter \"{0}: {1}\"",
|
||||||
"MessageBookshelfNoResultsForQuery": "No results for query",
|
"MessageBookshelfNoResultsForQuery": "No results for query",
|
||||||
@@ -821,6 +822,7 @@
|
|||||||
"MessageNoTasksRunning": "No Tasks Running",
|
"MessageNoTasksRunning": "No Tasks Running",
|
||||||
"MessageNoUpdatesWereNecessary": "No updates were necessary",
|
"MessageNoUpdatesWereNecessary": "No updates were necessary",
|
||||||
"MessageNoUserPlaylists": "You have no playlists",
|
"MessageNoUserPlaylists": "You have no playlists",
|
||||||
|
"MessageNoUserPlaylistsHelp": "Playlists are private. Only the user who creates them can see them.",
|
||||||
"MessageNotYetImplemented": "Not yet implemented",
|
"MessageNotYetImplemented": "Not yet implemented",
|
||||||
"MessageOpmlPreviewNote": "Note: This is a preview of the parsed OPML file. The actual podcast title will be taken from the RSS feed.",
|
"MessageOpmlPreviewNote": "Note: This is a preview of the parsed OPML file. The actual podcast title will be taken from the RSS feed.",
|
||||||
"MessageOr": "or",
|
"MessageOr": "or",
|
||||||
|
|||||||
@@ -286,7 +286,7 @@ class Book extends Model {
|
|||||||
const track = structuredClone(af)
|
const track = structuredClone(af)
|
||||||
track.title = af.metadata.filename
|
track.title = af.metadata.filename
|
||||||
track.startOffset = startOffset
|
track.startOffset = startOffset
|
||||||
track.contentUrl = `${global.RouterBasePath}/api/items/${libraryItemId}/file/${track.ino}`
|
track.contentUrl = `/api/items/${libraryItemId}/file/${track.ino}`
|
||||||
startOffset += track.duration
|
startOffset += track.duration
|
||||||
return track
|
return track
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -169,7 +169,7 @@ class PodcastEpisode extends Model {
|
|||||||
const track = structuredClone(this.audioFile)
|
const track = structuredClone(this.audioFile)
|
||||||
track.startOffset = 0
|
track.startOffset = 0
|
||||||
track.title = this.audioFile.metadata.filename
|
track.title = this.audioFile.metadata.filename
|
||||||
track.contentUrl = `${global.RouterBasePath}/api/items/${libraryItemId}/file/${track.ino}`
|
track.contentUrl = `/api/items/${libraryItemId}/file/${track.ino}`
|
||||||
return track
|
return track
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ class AudioTrack {
|
|||||||
this.duration = audioFile.duration
|
this.duration = audioFile.duration
|
||||||
this.title = audioFile.metadata.filename || ''
|
this.title = audioFile.metadata.filename || ''
|
||||||
|
|
||||||
this.contentUrl = `${global.RouterBasePath}/api/items/${itemId}/file/${audioFile.ino}`
|
this.contentUrl = `/api/items/${itemId}/file/${audioFile.ino}`
|
||||||
this.mimeType = audioFile.mimeType
|
this.mimeType = audioFile.mimeType
|
||||||
this.codec = audioFile.codec || null
|
this.codec = audioFile.codec || null
|
||||||
this.metadata = audioFile.metadata.clone()
|
this.metadata = audioFile.metadata.clone()
|
||||||
@@ -44,4 +44,4 @@ class AudioTrack {
|
|||||||
this.mimeType = 'application/vnd.apple.mpegurl'
|
this.mimeType = 'application/vnd.apple.mpegurl'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
module.exports = AudioTrack
|
module.exports = AudioTrack
|
||||||
|
|||||||
Reference in New Issue
Block a user