Compare commits

..

10 Commits

Author SHA1 Message Date
advplyr
aebb3ff413 Fix API including basepath in tracks contentUrl 2025-02-01 16:47:36 -06:00
advplyr
a58d486c44 Fix:Collapsed subseries showing parent series name on hover #3713 2025-01-31 17:18:23 -06:00
advplyr
4a76ba0226 Remove copy of series numbers on book cards 2025-01-31 17:11:57 -06:00
advplyr
7afff57b5e Merge pull request #3916 from nichwall/add_collection_help_text
Add collection and playlist help text
2025-01-30 17:50:21 -06:00
advplyr
2e13c5bd50 Fix no collections message, ui updates 2025-01-30 17:47:41 -06:00
advplyr
344de941ff Merge pull request #3919 from advplyr/fix_logger_fatal
Fix Logger.fatal to ensure crash_logs.txt is written to
2025-01-30 17:36:37 -06:00
advplyr
c3aad9486c Fix Logger.fatal to be a promise to ensure crash_logs.txt write 2025-01-30 17:27:32 -06:00
Nicholas Wallace
5c0cd98cb3 Add: collection and playlist help text to modal 2025-01-29 22:55:34 -07:00
Nicholas Wallace
8974c582fc Add: collection and playlist link to guide 2025-01-29 22:46:53 -07:00
advplyr
5ee6005112 Merge pull request #3914 from advplyr/progress_bar_visibility
Adds box shadow to progress bar on covers for visibility #3825
2025-01-29 18:05:07 -06:00
12 changed files with 59 additions and 25 deletions

View File

@@ -19,6 +19,14 @@
</div>
<div v-else-if="!totalShelves && initialized" class="w-full py-16">
<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 -->
<div v-if="entityName === 'items'" class="flex justify-center mt-2">
<ui-btn v-if="hasFilter" color="primary" @click="clearFilter">{{ $strings.ButtonClearFilter }}</ui-btn>
@@ -109,6 +117,11 @@ export default {
}
return this.$strings.MessageNoResults
},
emptyMessageHelp() {
if (this.page === 'collections') return this.$strings.MessageBookshelfNoCollectionsHelp
if (this.page === 'playlists') return this.$strings.MessageNoUserPlaylistsHelp
return ''
},
entityName() {
if (!this.page) return 'items'
return this.page

View File

@@ -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>
</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) -->
<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
},
seriesName() {
if (this.collapsedSeries?.name) return this.collapsedSeries.name
return this.series?.name || null
},
seriesSequence() {

View File

@@ -19,9 +19,20 @@
</template>
</transition-group>
</div>
<div v-if="!collections.length" class="flex h-32 items-center justify-center">
<p class="text-xl">{{ $strings.MessageNoCollections }}</p>
<div v-if="!collections.length" class="flex h-32 items-center justify-center text-center px-2">
<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 class="w-full h-px bg-white bg-opacity-10" />
<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">

View File

@@ -19,8 +19,18 @@
</template>
</transition-group>
</div>
<div v-if="!playlists.length" class="flex h-32 items-center justify-center">
<p class="text-xl">{{ $strings.MessageNoUserPlaylists }}</p>
<div v-if="!playlists.length" class="flex h-32 items-center justify-center text-center px-2">
<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 class="w-full h-px bg-white bg-opacity-10" />
<form @submit.prevent="submitCreatePlaylist">

View File

@@ -414,11 +414,8 @@ export default {
const audioEl = this.audioEl || document.createElement('audio')
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'
document.body.appendChild(audioEl)

View File

@@ -1,5 +1,5 @@
export default class AudioTrack {
constructor(track, userToken) {
constructor(track, userToken, routerBasePath) {
this.index = track.index || 0
this.startOffset = track.startOffset || 0 // Total time of all previous tracks
this.duration = track.duration || 0
@@ -9,20 +9,27 @@ export default class AudioTrack {
this.metadata = track.metadata || {}
this.userToken = userToken
this.routerBasePath = routerBasePath || ''
}
/**
* Used for CastPlayer
*/
get fullContentUrl() {
if (!this.contentUrl || this.contentUrl.startsWith('http')) return this.contentUrl
if (process.env.NODE_ENV === 'development') {
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() {
if (!this.contentUrl || this.contentUrl.startsWith('http')) return this.contentUrl
return this.contentUrl + `?token=${this.userToken}`
return `${this.routerBasePath}${this.contentUrl}?token=${this.userToken}`
}
}

View File

@@ -226,7 +226,7 @@ export default class PlayerHandler {
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.isHlsTranscode = true

View File

@@ -711,6 +711,7 @@
"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.",
"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",
"MessageBookshelfNoResultsForFilter": "No results for filter \"{0}: {1}\"",
"MessageBookshelfNoResultsForQuery": "No results for query",
@@ -821,6 +822,7 @@
"MessageNoTasksRunning": "No Tasks Running",
"MessageNoUpdatesWereNecessary": "No updates were necessary",
"MessageNoUserPlaylists": "You have no playlists",
"MessageNoUserPlaylistsHelp": "Playlists are private. Only the user who creates them can see them.",
"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.",
"MessageOr": "or",

View File

@@ -117,7 +117,7 @@ class Logger {
if (level < LogLevel.FATAL && level < this.logLevel) return
const consoleMethod = Logger.ConsoleMethods[levelName]
console[consoleMethod](`[${this.timestamp}] ${levelName}:`, ...args)
this.#logToFileAndListeners(level, levelName, args, source)
return this.#logToFileAndListeners(level, levelName, args, source)
}
trace(...args) {
@@ -141,7 +141,7 @@ class Logger {
}
fatal(...args) {
this.#log('FATAL', this.source, ...args)
return this.#log('FATAL', this.source, ...args)
}
note(...args) {

View File

@@ -286,7 +286,7 @@ class Book extends Model {
const track = structuredClone(af)
track.title = af.metadata.filename
track.startOffset = startOffset
track.contentUrl = `${global.RouterBasePath}/api/items/${libraryItemId}/file/${track.ino}`
track.contentUrl = `/api/items/${libraryItemId}/file/${track.ino}`
startOffset += track.duration
return track
})

View File

@@ -169,7 +169,7 @@ class PodcastEpisode extends Model {
const track = structuredClone(this.audioFile)
track.startOffset = 0
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
}

View File

@@ -29,7 +29,7 @@ class AudioTrack {
this.duration = audioFile.duration
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.codec = audioFile.codec || null
this.metadata = audioFile.metadata.clone()
@@ -44,4 +44,4 @@ class AudioTrack {
this.mimeType = 'application/vnd.apple.mpegurl'
}
}
module.exports = AudioTrack
module.exports = AudioTrack