This commit is contained in:
Faizan Zafar 2025-01-23 23:32:11 +09:00 committed by GitHub
commit 2980b15b0f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 65 additions and 6 deletions

View file

@ -34,6 +34,7 @@
ref="audioPlayer" ref="audioPlayer"
:chapters="chapters" :chapters="chapters"
:current-chapter="currentChapter" :current-chapter="currentChapter"
:libraryItem="streamLibraryItem"
:paused="!isPlaying" :paused="!isPlaying"
:loading="playerLoading" :loading="playerLoading"
:bookmarks="bookmarks" :bookmarks="bookmarks"

View file

@ -7,7 +7,11 @@
<ui-tooltip direction="bottom" :text="$strings.LabelVolume"> <ui-tooltip direction="bottom" :text="$strings.LabelVolume">
<controls-volume-control ref="volumeControl" v-model="volume" @input="setVolume" class="mx-2 hidden sm:block" /> <controls-volume-control ref="volumeControl" v-model="volume" @input="setVolume" class="mx-2 hidden sm:block" />
</ui-tooltip> </ui-tooltip>
<ui-tooltip v-if="hasEbookFile" direction="top" :text="$strings.ButtonOpenCurrentChapter">
<button :aria-label="$strings.ButtonOpenCurrentChapter" class="text-gray-300 hover:text-white mx-1 lg:mx-2" @mousedown.prevent @mouseup.prevent @click.stop="openEbook">
<span class="material-symbols text-2xl">auto_stories</span>
</button>
</ui-tooltip>
<ui-tooltip v-if="!hideSleepTimer" direction="top" :text="$strings.LabelSleepTimer"> <ui-tooltip v-if="!hideSleepTimer" direction="top" :text="$strings.LabelSleepTimer">
<button :aria-label="$strings.LabelSleepTimer" class="text-gray-300 hover:text-white mx-1 lg:mx-2" @mousedown.prevent @mouseup.prevent @click.stop="$emit('showSleepTimer')"> <button :aria-label="$strings.LabelSleepTimer" class="text-gray-300 hover:text-white mx-1 lg:mx-2" @mousedown.prevent @mouseup.prevent @click.stop="$emit('showSleepTimer')">
<span v-if="!sleepTimerSet" class="material-symbols text-2xl">snooze</span> <span v-if="!sleepTimerSet" class="material-symbols text-2xl">snooze</span>
@ -83,6 +87,7 @@ export default {
type: Array, type: Array,
default: () => [] default: () => []
}, },
libraryItem: Object,
sleepTimerSet: Boolean, sleepTimerSet: Boolean,
sleepTimerRemaining: Number, sleepTimerRemaining: Number,
sleepTimerType: String, sleepTimerType: String,
@ -180,6 +185,9 @@ export default {
useChapterTrack() { useChapterTrack() {
const _useChapterTrack = this.$store.getters['user/getUserSetting']('useChapterTrack') || false const _useChapterTrack = this.$store.getters['user/getUserSetting']('useChapterTrack') || false
return this.chapters.length ? _useChapterTrack : false return this.chapters.length ? _useChapterTrack : false
},
hasEbookFile() {
return this.libraryItem.media && this.libraryItem.media.ebookFile
} }
}, },
methods: { methods: {
@ -352,6 +360,9 @@ export default {
else if (action === this.$hotkeys.AudioPlayer.INCREASE_PLAYBACK_RATE) this.increasePlaybackRate() else if (action === this.$hotkeys.AudioPlayer.INCREASE_PLAYBACK_RATE) this.increasePlaybackRate()
else if (action === this.$hotkeys.AudioPlayer.DECREASE_PLAYBACK_RATE) this.decreasePlaybackRate() else if (action === this.$hotkeys.AudioPlayer.DECREASE_PLAYBACK_RATE) this.decreasePlaybackRate()
else if (action === this.$hotkeys.AudioPlayer.CLOSE) this.closePlayer() else if (action === this.$hotkeys.AudioPlayer.CLOSE) this.closePlayer()
},
openEbook() {
this.$store.commit('showEReader', { libraryItem: this.libraryItem, keepProgress: true })
} }
}, },
mounted() { mounted() {

View file

@ -305,7 +305,7 @@ export default {
}) })
} }
}, },
initEpub() { async initEpub() {
/** @type {EpubReader} */ /** @type {EpubReader} */
const reader = this const reader = this
@ -330,8 +330,26 @@ export default {
flow: 'paginated' flow: 'paginated'
}) })
// load saved progress await reader.book.ready
reader.rendition.display(this.savedEbookLocation || reader.book.locations.start) // load saved progress or initial chapter
var initialLocation = this.savedEbookLocation || this.initialChapterHref || reader.book.locations.start
try {
const initialChapterTitle = this.getCurrentAudioChapter()
if (initialChapterTitle) {
const href = this.findChapterHref(initialChapterTitle)
if (href) {
try {
initialLocation = 'text/' + href
} catch (error) {
console.error('Failed to navigate to chapter:', error)
}
}
}
} catch (error) {
return
}
reader.rendition.display(initialLocation)
reader.rendition.on('rendered', () => { reader.rendition.on('rendered', () => {
this.applyTheme() this.applyTheme()
@ -439,13 +457,41 @@ export default {
this.rendition.getContents().forEach((c) => { this.rendition.getContents().forEach((c) => {
c.addStylesheetRules(this.themeRules) c.addStylesheetRules(this.themeRules)
}) })
},
getCurrentAudioChapter() {
try {
var currentTime = this.$store.getters['user/getUserMediaProgress'](this.libraryItemId).currentTime
var audioBookChapters = this.$store.state.streamLibraryItem.media.chapters
} catch (error) {
return null
}
if (!audioBookChapters) return null
const chapter = audioBookChapters.find((chapter) => chapter.start <= currentTime && currentTime < chapter.end)
return chapter.title || audioBookChapters[audioBookChapters.length - 1].title
},
findChapterHref(title) {
const normalizeString = (str) => {
return str.replace(/[^a-zA-Z0-9]/g, '').toLowerCase()
}
const findInToc = (items) => {
for (let item of items) {
if (normalizeString(item.label) === normalizeString(title)) return item.href
if (item.subitems) {
const result = findInToc(item.subitems)
if (result) return result
}
}
return null
}
return findInToc(this.rendition.book.navigation.toc)
} }
}, },
mounted() { async mounted() {
this.windowWidth = window.innerWidth this.windowWidth = window.innerWidth
this.windowHeight = window.innerHeight this.windowHeight = window.innerHeight
window.addEventListener('resize', this.resize) window.addEventListener('resize', this.resize)
this.initEpub()
await this.initEpub()
}, },
beforeDestroy() { beforeDestroy() {
window.removeEventListener('resize', this.resize) window.removeEventListener('resize', this.resize)

View file

@ -52,6 +52,7 @@
"ButtonNextChapter": "Next Chapter", "ButtonNextChapter": "Next Chapter",
"ButtonNextItemInQueue": "Next Item in Queue", "ButtonNextItemInQueue": "Next Item in Queue",
"ButtonOk": "Ok", "ButtonOk": "Ok",
"ButtonOpenCurrentChapter": "Open Current Chapter",
"ButtonOpenFeed": "Open Feed", "ButtonOpenFeed": "Open Feed",
"ButtonOpenManager": "Open Manager", "ButtonOpenManager": "Open Manager",
"ButtonPause": "Pause", "ButtonPause": "Pause",