# Royallib ZIP / RTF `.doc` daily book extraction pattern

Use this when a user uploads a `*.zip` that appears to contain a `.doc` ebook from Royallib/Lib-like sources and wants scheduled daily digests.

## Pattern

1. **Inspect the ZIP locally** with Python `zipfile` rather than assuming the extension tells the real document type.
   - Filenames may appear mojibaked in terminal output.
   - The large inner `.doc` may actually be **RTF**, not binary Word.
2. **Copy/extract into stable project storage**:
   - `source/uploaded.zip`
   - `source/book.doc` or `source/book.rtf`
   - `text/book_full.txt`
   - `daily_fragments/`
   - `daily_outputs/`
   - `manifest.json`, `state.json`, accumulating Markdown file.
3. **Detect the real type** with `file source/book.doc`.
   - If it says `Rich Text Format data`, parse as RTF.
   - Russian Royallib RTF often uses ANSI / cp1251-escaped text (`\'xx` sequences), even when the RTF header is odd/mojibaked.
4. **RTF extraction fallback** when `unrtf`, `pandoc`, or `antiword` are unavailable:
   - parse RTF control words;
   - skip destinations such as `fonttbl`, `stylesheet`, `info`, `pict`, `object`, `listtable`, `header`, `footer`;
   - decode `\'xx` bytes as `cp1251`;
   - map paragraph controls (`\par`, `\line`) to newlines;
   - normalize whitespace and verify the first text page/paragraph is readable Cyrillic.
5. **Trim download boilerplate** before chunking when there is a clear title marker, but preserve title/author and preface.
6. **Chunk by paragraphs**, not raw character slices. For dense book-digest prompts, ~12k–18k characters per fragment is a good target; allow larger first fragments when preface sections are long.
7. **Create a stateful script in `~/.hermes/scripts/`** that emits JSON with `fragment_text`, metadata, output paths, and supports `--peek` so verification does not advance state.
8. **Verify before scheduling**:
   - full text character count is plausible;
   - fragment count and first/last fragment look sane;
   - `--peek` returns JSON and leaves `state.json` unchanged;
   - accumulating file exists;
   - cron job `next_run_at` matches the requested local time.

## Timezone pitfall

Hermes cron displays and schedules in UTC unless the schedule is already expressed for the scheduler timezone. When a user says “каждый день в 15:30” and prior context implies Asia/Singapore / Samui / Bali, schedule `30 7 * * *` and explicitly note that it equals 15:30 UTC+8. If no timezone is implied, ask or state the assumed timezone.

## Copyright

For copyrighted books, daily outputs should be transformative: summary, concepts, tools, questions, applications, and short rephrased formulations. Do not reproduce long passages from the source text.
