5.0 KiB
Deployment-controlled reading hours and quiz
The reader enforces reading hours on both GET /api/chapter and chapter page-image
requests under /lib/ (HTTP 423 outside hours). The dashboard, manga metadata,
covers, progress, reading-time summaries, scraper and administrator pages remain
available. A reader tab already open when a window ends checks access every 15
seconds and returns to the gate. Chapter images use Cache-Control: no-store when
the limiter is configured. Already downloaded images in a browser or files available
directly on disk cannot be recalled; this is a self-imposed server access rule, not
DRM. There is no schedule-changing API or UI. Signed-in readers and admins can
view the effective weekly schedule and timezone under Settings → Reading
hours; that page is read-only.
Docker configuration
Set these deployment variables in the Compose .env file next to
docker-compose.yml, then recreate only the reader. The reader service
passes them through to the container. READER_IMAGE selects a reader-only
release while APP_IMAGE continues to select the scraper and Sentinel image.
Leaving READING_WINDOWS_JSON empty disables the limiter. Day keys
are 0 Sunday through 6 Saturday. Each day has any number of [start,end]
intervals; an end earlier than its start carries into the next day. 24:00 is
valid only as an end. Intervals are start-inclusive and end-exclusive, resolved
using the IANA timezone, including daylight-saving changes.
READING_WINDOWS_JSON='{"0":[["08:00","01:00"]],"1":[["07:00","12:00"],["13:00","24:00"]],"2":[["07:00","24:00"]],"3":[["07:00","24:00"]],"4":[["07:00","24:00"]],"5":[["07:00","24:00"]],"6":[["08:00","01:00"]]}'
READING_TIMEZONE=Europe/Berlin
READING_QUIZ_UNLOCK_MINUTES=60
READING_QUIZ_CATALOG_PATH=/data/reading-quiz.json
The Monday split above illustrates multiple on/off periods; replace it with
[["07:00","24:00"]] for an uninterrupted weekday. The Saturday and Sunday
windows extend to 01:00 on the following mornings. A malformed timezone,
schedule, unlock length or catalog stops the reader at startup rather than
silently removing the restriction. READING_QUIZ_UNLOCK_MINUTES accepts 1–1440.
The scraper is independent and must not be restarted for this configuration.
Until a reviewed catalog is installed at READING_QUIZ_CATALOG_PATH, the
outside-hours gate cannot offer a quiz. It does not relax the schedule.
Question bank and progress watermark
The bank is a deployment-managed JSON file, separate from manga.json and from
the scraper. See config/reading-quiz.example.json.
Its manga keys are exact library folder IDs. Each question has a stable ID,
prompt, accepted answer variants, an evidence citation, and at least one
requires chapter ID. The chapter IDs are the reader's IDs (for example 1/12,
not the on-disk v01/c0012). Every required chapter must be marked completed
for that user before the question enters their pool. This supports a single
watermark or a set of specific sections. Five eligible questions are needed to
offer a quiz; an empty bank simply leaves outside-hours reading locked. A
question's answers and evidence never go to the browser.
The challenge randomly samples five progress-eligible questions across all
library manga, not only the one being opened. It asks them sequentially, accepts
unlimited retries, and has no answer timer. Accepted variants are normalized
for case, punctuation and accents; one typo is tolerated for answers of five
or more characters, two for answers of eleven or more. Starting a new visit
invalidates the previous challenge, and leaving the page abandons it. Passing
all five grants that user reading access across manga for the configured number
of minutes, persisted in db.json across reader restarts. Questions are not
shown before their watermark; this depends on the reader's existing
self-reported completion records.
Validate a proposed file with
node tools/validate-reading-quiz.js <catalog.json> before pointing the reader
at it. For an eventual research agent: write drafts with source citations,
aliases and proposed chapter watermarks, then have a human verify identity,
answer and spoiler boundary. Only a reviewed catalog should be copied to the
configured path and loaded by restarting the reader. No wiki or transcript
fetching is performed by the reader itself.
Testing and rollback
node tools/test-compose.js --reading-limit-ui creates a disposable Compose
fixture with two progress-qualified sample manga, tests chapter and image
denial, quiz flow and the one-hour unlock, then tears it down. Add --keep
to leave an isolated playable instance locked for manual review; its printed
URL and fixture path identify it. Main data and the running main scraper are
not mounted. To roll back a future main deployment, restore the previous
reader image and configuration, recreate only the reader, and preserve current
db.json and library. The additional readingAccess field is backward-safe.