Continue row: a run of more than N chapters in order also marks a reread

A done chapter after the head now counts as left again when it was finished
more than rereadDays before the head (default 7) or before a run of more
than rereadChapters chapters read in order up to the head (default 5).
Both are user settings under Library page; 0 turns a rule off.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
MaashkinoozheandClaude Opus 5.5 committed 2026-11-01 11:47:45 +01:00
1 parent 9b529d7709
commit c760141636
5 files changed
+49 -13

No files matched your search

+22 -4
View File
@@ -39,9 +39,9 @@ test('the continue row counts chapters left after the head, rereads included', {
let server;
try {
const library = path.join(root, 'library'), data = path.join(root, 'data');
for (const title of ['Moon Garden', 'Sun Field'])
for (const ch of ['c001 One', 'c002 Two', 'c003 Three', 'c004 Four']) {
const dir = path.join(library, title, 'v01', ch);
for (const [title, count] of [['Moon Garden', 4], ['Sun Field', 4], ['Star Path', 8]])
for (let n = 1; n <= count; n++) {
const dir = path.join(library, title, 'v01', `c00${n}`);
fs.mkdirSync(dir, { recursive: true });
fs.writeFileSync(path.join(dir, '001.png'), new Canvas(60, 90, [40, 60, 120]).png());
}
@@ -63,7 +63,25 @@ test('the continue row counts chapters left after the head, rereads included', {
// First read stopped after chapter 2: two chapters left. Finished: nothing left.
for (const ch of moon.slice(0, 2)) await done('Moon Garden', ch);
for (const ch of sun) await done('Sun Field', ch);
assert.deepEqual(await left(), { 'Moon Garden': 2, 'Sun Field': 0 });
assert.deepEqual(await left(), { 'Moon Garden': 2, 'Sun Field': 0, 'Star Path': 0 });
// Read all 8 chapters of Star Path, then reread 1-6 right away: more than 5 in a row is a reread
// even within the time limit; with a longer run setting, or the run rule off, it is not.
const star = await ids('Star Path');
for (const ch of star) await done('Star Path', ch);
await new Promise(resolve => setTimeout(resolve, 5));
for (const ch of star.slice(0, 5)) await done('Star Path', ch);
assert.equal((await left())['Star Path'], 0, 'five in a row is not yet a reread');
await done('Star Path', star[5]);
assert.equal((await left())['Star Path'], 2);
await post(alice, '/api/settings', { rereadChapters: 6 });
assert.equal((await left())['Star Path'], 0);
await post(alice, '/api/settings', { rereadChapters: 0 });
assert.equal((await left())['Star Path'], 0);
await post(alice, '/api/settings', { rereadChapters: 5, rereadDays: -1 });
const settings = (await get(alice, '/api/me')).settings;
assert.equal(settings.rereadDays, 7, 'invalid values are ignored');
assert.equal((await left())['Star Path'], 2);
// Unfinished head: the rest of that chapter is still left.
await post(alice, '/api/progress', { m: 'Moon Garden', ...moon[2], p: 0, n: 1 });