feat(books): include comics in non-audio requests

Keep books and comic archives under the existing ebook request kind so searches, ownership checks,
format preferences and release profiles agree without changing the API contract. Cover the combined
formats and library access rules with unit and end-to-end tests.

Ref #1748
This commit is contained in:
neon
2026-10-10 21:47:09 +00:00
parent e6c0275fdf
commit c91648eaac
14 changed files with 233 additions and 42 deletions
@@ -1,5 +1,5 @@
import { computed, ref, watch, type Ref } from 'vue'
import { getBookMediaProfile } from '@bookorbit/types'
import { BOOK_REQUEST_FORMATS_BY_MEDIA_KIND } from '@bookorbit/types'
import type { BookDetail, BookRequestAvailability, BookRequestMediaKind, BookRequestSubmitResult, CreateBookRequestPayload } from '@bookorbit/types'
import { api } from '@/lib/api'
import { pairHalfState, type PairHalfState } from '../requestPair'
@@ -23,9 +23,13 @@ export function useMissingFormatRequest(book: Ref<BookDetail | null>, enabled: R
const missing = computed<BookRequestMediaKind | null>(() => {
if (!book.value) return null
const profile = getBookMediaProfile(book.value.files)
if (profile.hasEbook && !profile.hasAudio) return 'audiobook'
if (profile.hasAudio && !profile.hasEbook) return 'ebook'
const formats = book.value.files
.filter((file) => file.role === 'content' || file.role === 'primary')
.map((file) => file.format?.toLowerCase() ?? '')
const hasReadable = formats.some((format) => BOOK_REQUEST_FORMATS_BY_MEDIA_KIND.ebook.includes(format))
const hasAudio = formats.some((format) => BOOK_REQUEST_FORMATS_BY_MEDIA_KIND.audiobook.includes(format))
if (hasReadable && !hasAudio) return 'audiobook'
if (hasAudio && !hasReadable) return 'ebook'
return null
})