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:
1 parent
9b529d7709
commit
c760141636
5 files changed
+49
-13
No files matched your search
@@ -120,7 +120,7 @@ function checkPw(pw, stored) {
|
||||
}
|
||||
const DUMMY_HASH = hashPw('x');
|
||||
const DEFAULTS = { startMode: 'last', lastMode: 'page', adapt: true, skipExtras: false, skipCovers: false, flowPageGap: true, pageTone: 'original', readingClock: false, readingStory: true,
|
||||
continueRow: true, readDate: 'hour', releaseDate: true, discoveryEnabled: false, discoveryReadingActivity: false, discoveryMature: false, zoom: {}, webhook: '', readerPerSession: true };
|
||||
continueRow: true, rereadDays: 7, rereadChapters: 5, readDate: 'hour', releaseDate: true, discoveryEnabled: false, discoveryReadingActivity: false, discoveryMature: false, zoom: {}, webhook: '', readerPerSession: true };
|
||||
const userSettingsOf = u => ({ ...DEFAULTS, ...u.settings, zoom: { ...(u.settings && u.settings.zoom) } });
|
||||
// With a login session, its locked reader settings (reader-sessions.js) win over the user's latest set.
|
||||
const settingsOf = (u, sess) => readerSessions.effective(userSettingsOf(u), sess);
|
||||
@@ -465,15 +465,23 @@ function continueOf(m, prog, s) {
|
||||
const next = m.chapters.slice(m.chapters.indexOf(last.ch) + 1).find(ok);
|
||||
return next ? { c: next.id, at, text: 'Read next · ' + next.label } : { c: last.ch.id, v: last.p.v, at, text: 'Read again · ' + last.ch.label };
|
||||
}
|
||||
// A chapter after the head counts as read in this pass only if it is done and was saved within this
|
||||
// gap before the head; older ones belong to an earlier pass, so the head is a reread.
|
||||
const REREAD_GAP_MS = 7 * 24 * 3600 * 1000;
|
||||
// Chapters still ahead of the head: never finished, or last read in an earlier pass. 0 = caught up.
|
||||
// A done chapter after the head belongs to an earlier pass (the head is a reread) when it was saved
|
||||
// more than `rereadDays` before the head, or before a run of more than `rereadChapters` chapters read
|
||||
// in order up to the head. 0 turns either rule off.
|
||||
function leftOf(m, prog, s) {
|
||||
const last = lastOf(m, prog);
|
||||
if (!last) return 0;
|
||||
const after = m.chapters.slice(m.chapters.indexOf(last.ch) + 1).filter(c => !(s.skipExtras && c.extra));
|
||||
return after.filter(c => { const p = prog[c.id]; return !p || !p.done || last.p.t - p.t > REREAD_GAP_MS; }).length
|
||||
const chapters = m.chapters.filter(c => c === last.ch || !(s.skipExtras && c.extra)), at = chapters.indexOf(last.ch);
|
||||
let runStart = last.p.t, run = 1;
|
||||
for (let i = at - 1; i >= 0; i--) {
|
||||
const p = prog[chapters[i].id];
|
||||
if (!p || !p.done || p.t > runStart) break;
|
||||
runStart = p.t; run++;
|
||||
}
|
||||
const gap = s.rereadDays > 0 ? s.rereadDays * 24 * 3600 * 1000 : Infinity;
|
||||
const passStart = s.rereadChapters > 0 && run > s.rereadChapters ? runStart : -Infinity;
|
||||
return chapters.slice(at + 1).filter(c => { const p = prog[c.id]; return !p || !p.done || last.p.t - p.t > gap || p.t < passStart; }).length
|
||||
+ (last.p.done ? 0 : 1);
|
||||
}
|
||||
// What a reader tab compares itself with (stale reading sessions, docs/architecture.md).
|
||||
@@ -612,6 +620,8 @@ const routes = {
|
||||
if (['flow', 'page', 'book'].includes(b.lastMode)) s.lastMode = b.lastMode;
|
||||
if (['original', 'inverted', 'sepia', 'dim', 'extra-dim'].includes(b.pageTone)) s.pageTone = b.pageTone;
|
||||
if (['off', 'date', 'hour'].includes(b.readDate)) s.readDate = b.readDate;
|
||||
if (Number.isInteger(b.rereadDays) && b.rereadDays >= 0 && b.rereadDays <= 3650) s.rereadDays = b.rereadDays;
|
||||
if (Number.isInteger(b.rereadChapters) && b.rereadChapters >= 0 && b.rereadChapters <= 1000) s.rereadChapters = b.rereadChapters;
|
||||
for (const k of ['adapt', 'skipExtras', 'skipCovers', 'flowPageGap', 'readingClock', 'readingStory', 'releaseDate', 'continueRow',
|
||||
'discoveryEnabled', 'discoveryReadingActivity', 'discoveryMature', 'readerPerSession']) if (typeof b[k] === 'boolean') s[k] = b[k];
|
||||
if (b.zoom && typeof b.zoom === 'object') {
|
||||
|
||||
Reference in new issue
Block a user