Skip to content

Chapter list: show chapters past 1000, and page the list 100 at a time from Continue - #89

Merged
AngeloSha merged 4 commits into
AngeloSha:mainfrom
Squeaks72:pr/chapter-list-paging
Sep 25, 2026
Merged

AngeloSha merged 4 commits into
AngeloSha:mainfrom
Squeaks72:pr/chapter-list-paging

Conversation

@Squeaks72

Copy link
Copy Markdown
Contributor

Summary

The bug. The series page and the reader both asked the books route for a single page of 1000 (/api/series/:id/books?size=1000). A series longer than that silently stopped at chapter 1000: One Piece (1,193 chapters on the server) listed 1–1000, and the reader's prev/next and jump list ended at 1000 too, although 1001+ were on disk and readable. The smart-offline planner (bff/src/routes/catalog.ts) had the same cap server-side, so a favourite read past chapter 1000 planned nothing: all its unread chapters were beyond the page.

The fix.

  • web/lib/seriesBooks.ts fetchAllBooks() walks the route page by page (1000 per request) until it has totalElements rows, stopping early on an empty page, with a 50-page backstop. The series page and the reader both use it. A 1,193-chapter series now makes two requests instead of one.
  • The planner asks for every chapter of each favourite, not the first 1000.

The list, a page at a time. Once every chapter is loaded, a 1,193-row list is a long scroll to reach where you are reading. The list now shows 100 rows a page (web/lib/chapterPages.ts), with a pager above and below it: first / previous / a picker that names each page by the rows it holds (901–1000) / next / last. It opens on the page holding the chapter Continue would open, so a reader on chapter 956 lands among the 900s. A tap on the pager pins a page. A new series, sort order or filter drops the pin and follows Continue again. The pages are cut from the merged rows (chapters, grey "not on the server" rows, run rows), so a grey row stays between the chapters it falls between, as it does in the unpaged list. Series of 100 rows or fewer show no pager.

Kept working with the rest of the page:

  • Mark all read, the per-row "mark earlier chapters", select mode and v0.43.0's read marks for chapters not held (MARK_CHUNK) all work on the full books / filtered lists, not the visible page, so they are unchanged. A pick made on one page stays picked when you turn to another.
  • A chapter chip in Sources & translations scrolls to that chapter's row (getElementById('ch-N')). With paging, that row may not be rendered at all. SourcesSheet takes a new optional onShowChapter(n), and the series page uses it to turn to the page holding the row before the scroll.

It is one topic, long chapter lists. The 1000-chapter cap is the fix, and the pager is the feature that makes the full list usable. docs/USAGE.md (section 4) describes the pager. New strings (Chapter pages, First page, Last page, of {n}) are translated in all eight locales. Previous/Next already existed.

Type

  • Fix
  • Feature
  • Docs
  • Refactor / chore

Testing

Re-run after rebasing onto v0.45.0 (91b41aa): bff 1857 tests, 1844 pass, 9 fail, 4 skipped — the same 9 embedded-Postgres entrypoint failures main has in this environment (main: 1857 / 1844 / 9 / 4), nothing new; web 437/437; both typechecks OK. The detail below is from the first run, on v0.44.0.
New tests:

  • web/test/seriesBooks.test.ts: against a fake paging route, 1,193 chapters come back in two requests (fails before: one size=1000 request stops at 1000); a short series is one request; an empty page ends the walk even when the count promised more.
  • web/test/chapterPages.test.ts: page count, the page holding a target (chapter 956 → page 9), slicing past chapter 1000, and clamping a stale page after a filter shrinks the list.

Run in node:24-alpine against a real postgres:16-alpine (TEST_DATABASE_URL set, so the SQL tests run), first on plain main (a8bc502) and then on this branch:

main (baseline) this branch
bff tsc --noEmit OK OK
bff tests 1834 tests: 1821 pass, 9 fail, 4 skipped same: 1834, 1821 pass, 9 fail, 4 skipped
web tsc --noEmit OK OK
web tests 421 / 421 427 / 427 (+6 new: 3 in seriesBooks, 3 in chapterPages)

The 9 bff failures are the same on both: the embedded-Postgres entrypoint tests (not ok 291–299), which cannot run in this sandbox. No new failures.

npm run test:i18n was not run: it is the puppeteer walk (test/e2e/i18n.mjs) that needs a running app and Chromium. The new keys were checked to exist in all eight locale files, and each file still parses as JSON.

Checklist

  • Focused scope (one topic)
  • Matches the existing TypeScript style
  • Docs updated if user-facing (docs/USAGE.md)
  • No new default sources hardcoded to specific sites (the engine system reaches sites by URL)

🤖 Generated with Claude Code

Squeaks72 and others added 4 commits September 24, 2026 10:27
A term submitted with a source chosen now asks only that source (&source= on
search-all) instead of fanning out to every one and answering with everything,
and the picker stays on screen so the filter is visible and clearable rather
than silently narrowing the results.

`source` only narrows the route's existing surfaceable() set, so an adult
source without adult=1, one above the account's age limit, or an unknown id
asks nobody and answers the empty shape. The search query's key now includes
the chosen source; discoverSearch.test.ts and discoverAdult.test.ts pin the
new key and the picker being mounted in both modes, and searchAll.int.test.ts
covers the narrowed fan-out. Documented in openapi.yaml, docs/api.md and
USAGE.md.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…t Continue

Chapter list
- The series page and the reader asked the books route for one page of
  1000, so One Piece's chapters 1001+ never appeared in the list or in the
  reader's prev/next/jump list. lib/seriesBooks.ts fetchAllBooks() walks
  every page (tested). The smart-offline planner had the same cap
  server-side.
- The list now renders 100 rows a page (lib/chapterPages.ts, tested) with
  a pager above and below (first/prev/range picker/next/last). It opens on
  the page holding the "Continue" chapter; a tap on the pager pins a page,
  and a new series, sort, or filter follows Continue again. A chapter chip
  in Sources & translations turns to the page holding that row before it
  scrolls to it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…per book

On top of @Squeaks72's paging, which fixes a real bug on main -- Continue opened chapter 1 for anyone past
chapter 1000:

- The picker named pages by row position. Ghost, run and "show all" rows are rows but not chapters, and
  newest first labelled the page holding 1193-1094 "1-100". Pages are now named by the first and last chapter
  numbers they show, in the list's own order, and the count beside it is chapters.
- The page followed Continue live, so expanding an older-chapters run, "Show all" or "Mark all read" flipped
  the list away from what the reader was doing. It is decided once per series, sort and filter, once the
  chapters and the sources' listing (whose ghost rows would shift it) have both arrived.
- A scan between the two requests could hand the same book back at the 1000 boundary: two rows, one React key.
  Kept once.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ranch

The PRs merge in order, so each branch carries the ones before it and merges without conflicts.
AngeloSha added a commit to Squeaks72/uchiyomi that referenced this pull request Sep 25, 2026
The PRs merge in order, so each branch carries the ones before it and merges without conflicts.

# Conflicts:
#	web/public/locales/ar.json
#	web/public/locales/de.json
#	web/public/locales/es.json
#	web/public/locales/fr.json
#	web/public/locales/ja.json
#	web/public/locales/pt-BR.json
#	web/public/locales/ru.json
#	web/public/locales/zh.json
@AngeloSha
AngeloSha merged commit d8633e8 into AngeloSha:main Sep 25, 2026
12 checks passed
AngeloSha added a commit that referenced this pull request Sep 25, 2026
… extension engine

Right-to-left paging (#90), one key per page (#92), reader settings pinned to
a source (#95), type-to-search (#94), chapter names (#84), a chapter list that
pages past chapter 1000 (#89), Discover keeping its source through a search
(#87) and an 18+ filter an admin can widen (#86) -- seven merged with fixes on
top, one as it was. The extension engine (Suwayomi-Server, headless) gets the
desktop app's memory cap in every compose file (#72).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@AngeloSha

Copy link
Copy Markdown
Owner

Thanks, and good catch. On main, Continue opens chapter 1 for anyone reading past chapter 1000, which is a real bug.

Three fixes on top:

  • The page picker named pages by row position, but ghost rows, older-chapter runs and "Show all" are rows too, and newest-first labelled the page holding 1193 to 1094 as "1–100". Pages are named by the chapter numbers they show now.
  • The list followed Continue live, so expanding an older-chapters run, "Show all" or "Mark all read" flipped you to another page. It picks the page once per series, sort and filter, after the listing has loaded.
  • If a scan landed between the two requests, the same book could come back twice at the 1000 boundary. It's kept once now.

Merged, and it shipped in v0.46.0.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants