Compare commits

..

5 Commits

Author SHA1 Message Date
advplyr b876256736 Audiobook tools page include edit item button and item title linked to item page 2025-05-08 17:17:44 -05:00
advplyr 3ce6e45761 Support m4b encoder tool for single m4b audiobooks 2025-05-08 17:08:11 -05:00
advplyr 5ac6b85da1 Merge pull request #4270 from advplyr/episode_secondary_sorts
Update episode secondary sort to pubDate and episode #4262
2025-05-07 17:45:53 -05:00
advplyr 69e0a0732a Update episode secondary sort to pubDate and episode #4262 2025-05-07 17:30:07 -05:00
advplyr 087835a9f3 Merge pull request #4266 from advplyr/hls_stream_url_update
Update HLS stream endpoints to not include user token
2025-05-06 17:39:16 -05:00
3 changed files with 51 additions and 25 deletions
+1 -8
View File
@@ -74,19 +74,12 @@ export default {
mediaTracks() { mediaTracks() {
return this.media.tracks || [] return this.media.tracks || []
}, },
isSingleM4b() {
return this.mediaTracks.length === 1 && this.mediaTracks[0].metadata.ext.toLowerCase() === '.m4b'
},
chapters() { chapters() {
return this.media.chapters || [] return this.media.chapters || []
}, },
showM4bDownload() { showM4bDownload() {
if (!this.mediaTracks.length) return false if (!this.mediaTracks.length) return false
return !this.isSingleM4b return true
},
showMp3Split() {
if (!this.mediaTracks.length) return false
return this.isSingleM4b && this.chapters.length
}, },
queuedEmbedLIds() { queuedEmbedLIds() {
return this.$store.state.tasks.queuedEmbedLIds || [] return this.$store.state.tasks.queuedEmbedLIds || []
@@ -1,4 +1,3 @@
<template> <template>
<div id="lazy-episodes-table" class="w-full py-6"> <div id="lazy-episodes-table" class="w-full py-6">
<div class="flex flex-wrap flex-col md:flex-row md:items-center mb-4"> <div class="flex flex-wrap flex-col md:flex-row md:items-center mb-4">
@@ -176,6 +175,13 @@ export default {
return episodeProgress && !episodeProgress.isFinished return episodeProgress && !episodeProgress.isFinished
}) })
.sort((a, b) => { .sort((a, b) => {
// Swap values if sort descending
if (this.sortDesc) {
const temp = a
a = b
b = temp
}
let aValue let aValue
let bValue let bValue
@@ -194,10 +200,23 @@ export default {
if (!bValue) bValue = Number.MAX_VALUE if (!bValue) bValue = Number.MAX_VALUE
} }
if (this.sortDesc) { const primaryCompare = String(aValue).localeCompare(String(bValue), undefined, { numeric: true, sensitivity: 'base' })
return String(bValue).localeCompare(String(aValue), undefined, { numeric: true, sensitivity: 'base' }) if (primaryCompare !== 0 || this.sortKey === 'publishedAt') return primaryCompare
// When sorting by season, secondary sort is by episode number
if (this.sortKey === 'season') {
const aEpisode = a.episode || ''
const bEpisode = b.episode || ''
const secondaryCompare = String(aEpisode).localeCompare(String(bEpisode), undefined, { numeric: true, sensitivity: 'base' })
if (secondaryCompare !== 0) return secondaryCompare
} }
return String(aValue).localeCompare(String(bValue), undefined, { numeric: true, sensitivity: 'base' })
// Final sort by publishedAt
let aPubDate = a.publishedAt || Number.MAX_VALUE
let bPubDate = b.publishedAt || Number.MAX_VALUE
return String(aPubDate).localeCompare(String(bPubDate), undefined, { numeric: true, sensitivity: 'base' })
}) })
}, },
episodesList() { episodesList() {
+27 -13
View File
@@ -2,7 +2,14 @@
<div id="page-wrapper" class="bg-bg page p-8 overflow-auto relative" :class="streamLibraryItem ? 'streaming' : ''"> <div id="page-wrapper" class="bg-bg page p-8 overflow-auto relative" :class="streamLibraryItem ? 'streaming' : ''">
<div class="flex items-center justify-center mb-6"> <div class="flex items-center justify-center mb-6">
<div class="w-full max-w-2xl"> <div class="w-full max-w-2xl">
<p class="text-2xl mb-2">{{ $strings.HeaderAudiobookTools }}</p> <div class="flex items-center mb-4">
<nuxt-link :to="`/item/${libraryItem.id}`" class="hover:underline">
<h1 class="text-lg lg:text-xl">{{ mediaMetadata.title }}</h1>
</nuxt-link>
<button class="w-7 h-7 flex items-center justify-center mx-4 hover:scale-110 duration-100 transform text-gray-200 hover:text-white" @click="editItem">
<span class="material-symbols text-base">edit</span>
</button>
</div>
</div> </div>
<div class="w-full max-w-2xl"> <div class="w-full max-w-2xl">
<div class="flex justify-end"> <div class="flex justify-end">
@@ -13,7 +20,7 @@
<div class="flex justify-center mb-2"> <div class="flex justify-center mb-2">
<div class="w-full max-w-2xl"> <div class="w-full max-w-2xl">
<p class="text-xl">{{ $strings.HeaderMetadataToEmbed }}</p> <p class="text-lg">{{ $strings.HeaderMetadataToEmbed }}</p>
</div> </div>
<div class="w-full max-w-2xl"></div> <div class="w-full max-w-2xl"></div>
</div> </div>
@@ -266,9 +273,6 @@ export default {
audioFiles() { audioFiles() {
return (this.media.audioFiles || []).filter((af) => !af.exclude) return (this.media.audioFiles || []).filter((af) => !af.exclude)
}, },
isSingleM4b() {
return this.audioFiles.length === 1 && this.audioFiles[0].metadata.ext.toLowerCase() === '.m4b'
},
streamLibraryItem() { streamLibraryItem() {
return this.$store.state.streamLibraryItem return this.$store.state.streamLibraryItem
}, },
@@ -276,14 +280,10 @@ export default {
return this.media.chapters || [] return this.media.chapters || []
}, },
availableTools() { availableTools() {
if (this.isSingleM4b) { return [
return [{ value: 'embed', text: this.$strings.LabelToolsEmbedMetadata }] { value: 'embed', text: this.$strings.LabelToolsEmbedMetadata },
} else { { value: 'm4b', text: this.$strings.LabelToolsM4bEncoder }
return [ ]
{ value: 'embed', text: this.$strings.LabelToolsEmbedMetadata },
{ value: 'm4b', text: this.$strings.LabelToolsM4bEncoder }
]
}
}, },
taskFailed() { taskFailed() {
return this.isTaskFinished && this.task.isFailed return this.isTaskFinished && this.task.isFailed
@@ -431,10 +431,24 @@ export default {
}, },
taskUpdated(task) { taskUpdated(task) {
this.processing = !task.isFinished this.processing = !task.isFinished
},
editItem() {
this.$store.commit('showEditModal', this.libraryItem)
},
libraryItemUpdated(libraryItem) {
if (libraryItem.id === this.libraryItem.id) {
this.libraryItem = libraryItem
this.fetchMetadataEmbedObject()
}
} }
}, },
mounted() { mounted() {
this.init() this.init()
this.$eventBus.$on(`${this.libraryItem.id}_updated`, this.libraryItemUpdated)
},
beforeDestroy() {
this.$eventBus.$off(`${this.libraryItem.id}_updated`, this.libraryItemUpdated)
} }
} }
</script> </script>