feat(books): filter read-along titles

Expose read-along EPUBs as an additive format filter while preserving ordinary EPUB matching and existing client compatibility.

Closes #1583
This commit is contained in:
neon
2026-10-21 05:18:37 +00:00
parent d1cc18dc51
commit edc5e41105
14 changed files with 159 additions and 29 deletions
+2
View File
@@ -39,6 +39,8 @@ export const SERVER_FEATURES = [
"metadata-search-results-per-provider",
/** Book and custom date filters accept the `moreThanAgo` rolling-boundary operator. */
"relative-date-ranges",
/** The `format` book filter accepts `epub:readalong` for EPUBs with media overlays. */
"read-along-filter",
] as const;
export type ServerFeature = (typeof SERVER_FEATURES)[number];
+6 -1
View File
@@ -8,12 +8,17 @@ import type { CoverAspectRatio } from "./library";
import { DEFAULT_FORMAT_PRIORITY } from "./library";
import type { SeriesIndex } from "./series-index";
import type { EpubMediaOverlayCapability } from "./epub";
import { READ_ALONG_FORMAT_PRIORITY } from "./format-priority";
// Derived rather than duplicated: these two lists describe the same set of formats,
// and maintaining them separately let BOOK_FORMATS fall behind on azw and kepub.
export const BOOK_FORMATS = DEFAULT_FORMAT_PRIORITY;
export type BookFormat = (typeof BOOK_FORMATS)[number];
/** Values accepted by the format filter. Read-along is an edition key, not a physical file format. */
export const BOOK_FILTER_FORMATS = [...BOOK_FORMATS, READ_ALONG_FORMAT_PRIORITY] as const;
export type BookFilterFormat = (typeof BOOK_FILTER_FORMATS)[number];
/** Exported as an ordered list too, so a form offering these cannot drift from what matches them. */
export const AUDIO_FORMAT_LIST = ["m4b", "mp3", "m4a", "opus", "ogg", "flac"] as const;
const AUDIO_FORMATS = new Set<string>(AUDIO_FORMAT_LIST);
@@ -440,7 +445,7 @@ export type BooksPage = {
};
export type BookFormatFacet = {
format: BookFormat;
format: BookFilterFormat;
count: number;
};