diff --git a/docs-developers/frontend/state-and-data.md b/docs-developers/frontend/state-and-data.md index a0c4b7a..18156ab 100644 --- a/docs-developers/frontend/state-and-data.md +++ b/docs-developers/frontend/state-and-data.md @@ -113,8 +113,20 @@ file/chapter list, in both the wide and phone branches, following the section-per-concern pattern (the same shape as the bookmarks/notes sections). It shows a description (collapsed past ~300 characters with a show-more toggle), compact production details (publisher, release date, first published, an -"abridged" badge), a horizontal **more in this series** rail, and a quiet **View -on AudioSilo Meta** link. +"abridged" badge), a **Characters** section, a **Story so far** recap section, a +horizontal **more in this series** rail, and a quiet **View on AudioSilo Meta** +link. + +The **Characters** and **Story so far** sections are the community expressive +layer (`work.characters` / `work.recaps`, the `BookMetaCharacter` / +`BookMetaRecap` types). They are spoiler-aware and rendered closed by default: +each character card shows name/role/aliases and "from chapter N" up front, with a +per-card accordion for the own-words description (no blur - a tap reveals it); +each recap likewise opens only when tapped, so the reader goes only as far as +they have listened. Both are absent from the envelope when the upstream has +none, so a work without them simply shows no such section. Pure label helpers +(`roleLabelKey`, `revealFromStart`, `recapDescriptor`, `sortRecaps`) are +unit-tested, and the strings live under `book.meta.*` in all locale catalogs. Three details make it safe to add to a screen everyone sees: diff --git a/docs-developers/server/api/reference.md b/docs-developers/server/api/reference.md index 2ce20de..2b11573 100644 --- a/docs-developers/server/api/reference.md +++ b/docs-developers/server/api/reference.md @@ -700,7 +700,24 @@ Response `200` on a match: "authors": [{ "id": "andy-weir", "name": "Andy Weir" }], "language": "en", "first_published": "2011", - "description": "An astronaut is stranded on Mars…" + "description": "An astronaut is stranded on Mars…", + "characters": [ + { + "id": "mark-watney", + "name": "Mark Watney", + "aliases": ["The Martian"], + "role": "protagonist", + "reveal": { "chapter": 1 }, + "description": "The stranded astronaut, an engineer-botanist…" + } + ], + "recaps": [ + { + "through": { "chapter": 6 }, + "scope": "book", + "text": "Watney has survived the storm and taken stock of Hab…" + } + ] }, "recording": { "id": "podium-2013", @@ -740,6 +757,30 @@ work's position in that series; `series[].works` is the full ordered rail, **including the current work** (the client filters it out before drawing a "more in this series" row). Positions are strings ("1", "2.5", "1-3.5"). +`work.characters` and `work.recaps` are the community **expressive layer** (the +CC BY-SA content, spoiler-tagged and position-keyed); both are `omitempty`, so +they are absent when the upstream has none. A **position** is +`{ "chapter": = 0> }` on the work's own, edition-independent timeline (the +logical work chapter, 1-based; `0` = front matter / prior-book knowledge), which +the client maps onto its recording's chapters. + +- Each **character** carries an `id` (unique within the work, not global), a + `name`, optional `aliases` and `role` (`protagonist`/`antagonist`/`supporting`/ + `minor`), a `reveal` position (where the character is first disclosed - the + spoiler gate), and an own-words `description`. Recurring characters are + re-described per book (Kindle-X-Ray style), so a client reveals only up to + where the listener is. +- Each **recap** carries a `through` position (safe to show once the listener has + finished that chapter), an optional `scope` (`book` or `series` - a + `chapter: 0` + `series` recap is the "previously, in earlier books" summary), + and own-words `text`. + +These fields are additive: they are passed straight through from the upstream +`GET /works/{id}` (see the [three-repo seam](../../architecture/cross-repo-contract.md)), +not composed or reshaped like `recording`/`series`. The one field the server +drops is the character cross-reference (`xref`) - it is not exposed to clients. A +client that ignores these fields is unaffected. + When the book has neither an `asin` nor an `isbn`, or the upstream reports no match, the response is `200 { "matched": false }` - a normal, non-error result that the client treats as "nothing to show": diff --git a/docs-users/listening/browsing.md b/docs-users/listening/browsing.md index 5b85f33..5099d60 100644 --- a/docs-users/listening/browsing.md +++ b/docs-users/listening/browsing.md @@ -56,10 +56,12 @@ If the same book exists in more than one place (say, an M4B copy and an MP3 copy Some books show an extra section below the chapters with more about the title: - An **About** description of the story, and production details such as the **publisher**, **release date** and when the work was **first published**. +- A **Characters** section - community-written cards for the people in the book. Each card shows the name, role and any aliases, plus which chapter the character first appears in; tap a card to reveal its short description. Cards stay closed until you tap them, so you decide when to read on. +- A **Story so far** section - short "what's happened up to here" recaps, each labelled with the chapter it's safe to read after. They stay closed by default, so you only open the one for as far as you've listened and don't spoil what's ahead. A recap marked for the very start reads "Previously, in earlier books" - a catch-up from earlier in the series. - A **More in this series** row - other books in the same series, each opening its page on the metadata site so you can see what to read next. - A **View on AudioSilo Meta** link to the book's full entry. -This information comes from the **AudioSilo community metadata database** at [meta.audiosilo.app](https://meta.audiosilo.app), a free, community-run catalogue of audiobook details. It appears only when the book can be matched (it carries an ASIN or ISBN) and your server has the metadata lookup switched on. If a book has no extra section, it simply isn't matched or your admin has turned the feature off - nothing else on the page changes. A server admin can switch the lookup on or off at any time from the admin console's Overview section (see the [console tour](../admin/console-tour.md#community-metadata-lookup)); when it is off, no book shows this section. +This information comes from the **AudioSilo community metadata database** at [meta.audiosilo.app](https://meta.audiosilo.app), a free, community-run catalogue of audiobook details. It appears only when the book can be matched (it carries an ASIN or ISBN) and your server has the metadata lookup switched on. The **Characters** and **Story so far** sections are contributed by the community, so a matched book shows them only once someone has written them - many books will have the About and series details but not these yet. If a book has no extra section, it simply isn't matched or your admin has turned the feature off - nothing else on the page changes. A server admin can switch the lookup on or off at any time from the admin console's Overview section (see the [console tour](../admin/console-tour.md#community-metadata-lookup)); when it is off, no book shows this section. ## Search