mirror of
https://github.com/bookorbit/bookorbit.git
synced 2026-11-03 00:11:37 -06:00
fix(reader,dashboard): handle audiobook progress reliably
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
|
||||
import { computed, onMounted, onUnmounted, ref, watch, type WatchStopHandle } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import {
|
||||
Bookmark,
|
||||
@@ -70,6 +70,7 @@ const progress = useAudioProgress(props.bookId)
|
||||
// ── Queue (created lazily after files load) ───────────────────────────────────
|
||||
|
||||
let queue: ReturnType<typeof useAudioQueue> | null = null
|
||||
let stopQueuePlayingWatch: WatchStopHandle | null = null
|
||||
const isPlaying = ref(false)
|
||||
const currentPosition = ref(0)
|
||||
const currentFileIndex = ref(0)
|
||||
@@ -100,6 +101,16 @@ function initQueue(startFileId: number, startPosition: number) {
|
||||
queue.goToFile(startFileId, startPosition)
|
||||
queue.setSpeed(settings.playbackSpeed.value)
|
||||
queue.setVolume(settings.volume.value)
|
||||
stopQueuePlayingWatch?.()
|
||||
stopQueuePlayingWatch = watch(
|
||||
queue.isPlaying,
|
||||
(playing) => {
|
||||
if (isPlaying.value !== playing) {
|
||||
isPlaying.value = playing
|
||||
}
|
||||
},
|
||||
{ immediate: true },
|
||||
)
|
||||
syncRefs()
|
||||
currentPosition.value = startPosition
|
||||
currentFileIndex.value = queue.currentIndex.value
|
||||
@@ -141,7 +152,6 @@ function startTicker() {
|
||||
if (!queue) return
|
||||
const pos = queue.position()
|
||||
currentPosition.value = pos
|
||||
isPlaying.value = queue.isPlaying.value
|
||||
currentFileIndex.value = queue.currentIndex.value
|
||||
|
||||
if (queue.isPlaying.value) {
|
||||
@@ -196,6 +206,8 @@ let mounted = true
|
||||
|
||||
onUnmounted(() => {
|
||||
mounted = false
|
||||
stopQueuePlayingWatch?.()
|
||||
stopQueuePlayingWatch = null
|
||||
queue?.destroy()
|
||||
stopTicker()
|
||||
progress.flush()
|
||||
|
||||
@@ -15,6 +15,7 @@ import type {
|
||||
import { DB } from '../../db';
|
||||
import * as schema from '../../db/schema';
|
||||
import {
|
||||
audiobookProgress,
|
||||
annotations,
|
||||
authors,
|
||||
bookAuthors,
|
||||
@@ -63,13 +64,30 @@ export class DashboardWidgetRepository {
|
||||
async getCurrentlyReadingBooks(userId: number, accessibleLibraryIds: number[]): Promise<CurrentlyReadingWidgetData> {
|
||||
if (accessibleLibraryIds.length === 0) return { books: [] };
|
||||
|
||||
const mergedProgress = sql<number>`
|
||||
coalesce(
|
||||
(
|
||||
case
|
||||
when ${readingProgress.updatedAt} is not null
|
||||
and (${audiobookProgress.updatedAt} is null or ${readingProgress.updatedAt} >= ${audiobookProgress.updatedAt})
|
||||
then ${readingProgress.percentage}
|
||||
else ${audiobookProgress.percentage}
|
||||
end
|
||||
),
|
||||
${readingProgress.percentage},
|
||||
${audiobookProgress.percentage},
|
||||
0
|
||||
)
|
||||
`;
|
||||
const mergedLastReadAt = sql<Date | null>`coalesce(${readingProgress.updatedAt}, ${audiobookProgress.updatedAt})`;
|
||||
|
||||
const rows = await this.db
|
||||
.select({
|
||||
bookId: books.id,
|
||||
title: bookMetadata.title,
|
||||
progress: readingProgress.percentage,
|
||||
progress: mergedProgress,
|
||||
coverSource: bookMetadata.coverSource,
|
||||
lastReadAt: readingProgress.updatedAt,
|
||||
lastReadAt: mergedLastReadAt,
|
||||
fileId: bookFiles.id,
|
||||
fileFormat: bookFiles.format,
|
||||
})
|
||||
@@ -78,6 +96,7 @@ export class DashboardWidgetRepository {
|
||||
.innerJoin(bookMetadata, eq(bookMetadata.bookId, books.id))
|
||||
.leftJoin(bookFiles, eq(bookFiles.id, books.primaryFileId))
|
||||
.leftJoin(readingProgress, and(isNotNull(bookFiles.id), eq(readingProgress.bookFileId, bookFiles.id), eq(readingProgress.userId, userId)))
|
||||
.leftJoin(audiobookProgress, and(eq(audiobookProgress.bookId, books.id), eq(audiobookProgress.userId, userId)))
|
||||
.where(
|
||||
and(
|
||||
eq(userBookStatus.userId, userId),
|
||||
@@ -85,7 +104,7 @@ export class DashboardWidgetRepository {
|
||||
inArray(books.libraryId, accessibleLibraryIds),
|
||||
),
|
||||
)
|
||||
.orderBy(desc(sql`coalesce(${readingProgress.updatedAt}, ${userBookStatus.updatedAt})`))
|
||||
.orderBy(desc(sql`coalesce(${readingProgress.updatedAt}, ${audiobookProgress.updatedAt}, ${userBookStatus.updatedAt})`))
|
||||
.limit(CURRENTLY_READING_LIMIT);
|
||||
|
||||
if (rows.length === 0) return { books: [] };
|
||||
|
||||
Reference in New Issue
Block a user