README and requirements: metadata rules and link drops in plain English

This commit is contained in:
Audiobook Producer
2026-10-18 13:25:01 -05:00
parent 9287ea8e16
commit 889b775a58
2 changed files with 16 additions and 5 deletions
+12 -5
View File
@@ -1,13 +1,14 @@
# Drop a PDF here to get an audiobook # Drop a PDF (or a link to one) here to get an audiobook
**What you do** **What you do**
1. Put the PDF in this folder (`_incoming/`). In Gitea: open `_incoming`, choose **Add file > Upload file**, drop the PDF, commit to `main`. 1. Put the PDF in this folder (`_incoming/`). In Gitea: open `_incoming`, choose **Add file > Upload file**, drop the PDF, commit to `main`.
**Or drop a link instead:** create a small text file here, for example `science-of-breath.url` (or `.txt`), whose content is just the web address of the PDF, like `https://example.org/books/science-of-breath.pdf`. A Windows internet shortcut (`.url` with a `URL=` line) works too. An arXiv page address (`https://arxiv.org/abs/2401.01234`) is turned into the PDF address automatically.
2. That is all. Nothing else to click, nobody to ask. 2. That is all. Nothing else to click, nobody to ask.
**What happens next (automatic, no bot)** **What happens next (automatic, no bot)**
A job on the 5060 machine reads the PDF, cleans the text, finds every chapter, writes the narration script and the license note, speaks every chapter in the locked voice (Michael, Chatterbox), builds one MP3 per chapter plus opening credits, closing credits and a retail sample, checks every file against the Audible/ACX numbers, and commits the finished book back to `main`. The PDF moves out of `_incoming/` in that same commit. A job on the 5060 machine (for a link: first downloads the PDF, follows redirects, refuses anything over 300 MB, and checks it really is a PDF) reads the PDF, cleans the text, finds every chapter, writes the narration script and the license note, speaks every chapter in the locked voice (Michael, Chatterbox), builds one MP3 per chapter plus opening credits, closing credits and a retail sample, checks every file against the Audible/ACX numbers, and commits the finished book back to `main`. The PDF (or the link file) moves out of `_incoming/` in that same commit. For a link, the downloaded PDF is stored in the book folder and the address is recorded in `book.json` as `source_url`.
**Where the audio appears** **Where the audio appears**
@@ -17,13 +18,19 @@ Example: `books/clark-glenn/the-man-who-tapped-the-secrets-of-the-universe/audio
**How to see progress** **How to see progress**
Open the repo's **Actions** tab (https://gitea.vps1.afterthedemo.com/Ty_Tech/old-books/actions). The run named `audiobook` is yours. Green = finished and committed. Red = it stopped, and the log says which step failed and why. A red run commits nothing and leaves the PDF here; fix the cause, then push anything that touches the PDF again, or use **Run workflow** on the Actions page and give it the PDF path. Open the repo's **Actions** tab (https://gitea.vps1.afterthedemo.com/Ty_Tech/old-books/actions). The run named `audiobook` is yours. Green = finished and committed. Red = it stopped, and the log says which step failed and why (for a link: bad address, server error, not a PDF, too large, timed out). A red run commits nothing and leaves the PDF or link file here; fix the cause, then push anything that touches the PDF again, or use **Run workflow** on the Actions page and give it the PDF path.
Long books take hours. About 1 hour of audio takes about 30 minutes to render. Long books take hours. About 1 hour of audio takes about 30 minutes to render.
**Good to know** **Good to know**
- Title and author are read from the PDF. If the PDF has no "By <Name>" line, the file name `Some Title - by First Last.pdf` is used. If neither works, the run fails and says so; then add a small file next to the PDF with the same name and `.json`, for example `my-book.json` containing `{"title": "My Book", "author": "First Last"}`. - **Title and author never stop a run.** They are found in this order, and `book.json` records where each came from (`metadata_sources`):
- Scanned pages with no text layer are OCRed automatically. OCR mistakes are listed in `warnings.log`. 1. A small file next to the PDF with the same name and `.json`, e.g. `my-book.json` containing `{"title": "My Book", "author": "First Last"}`. This always wins.
2. Title: the PDF's own Title property. Author: a "By First Last" line on the first pages (this beats the PDF's Author property, which is often a typesetter or "admin"), then the PDF's Author property.
3. If the first pages are scans, they are read by OCR (up to 10 pages), and a name printed right under the title also counts as the author.
4. The file name: `Some Title - by First Last.pdf`, or just the cleaned name (`2015.47927.Science-Of-Breath.pdf` becomes "Science Of Breath"). For a link, the name from the web address is used (and then the link file's own name).
5. No author anywhere: the author is "Unknown" and the book goes to `books/unknown/<title>/`. Nothing at all: the title comes from the file name.
Whenever a fallback is used, a line is added to `warnings.log` (`ingest-metadata`). To fix a wrong guess later, add the `.json` file and drop the PDF again.
- Scanned pages with no text layer are OCRed automatically (copy-protected PDFs are unlocked in the scratch copy only; your original is stored untouched). OCR mistakes are listed in `warnings.log`.
- Dropping the same PDF again skips audio that already exists. - Dropping the same PDF again skips audio that already exists.
- License status defaults to unknown and never blocks anything. Nothing is published anywhere outside this repo. - License status defaults to unknown and never blocks anything. Nothing is published anywhere outside this repo.
- Summaries (chapter preview, chapter-end summary, mid-chapter summary) are off. Turn them on per book in `book.json` under `summaries`. - Summaries (chapter preview, chapter-end summary, mid-chapter summary) are off. Turn them on per book in `book.json` under `summaries`.
+4
View File
@@ -137,3 +137,7 @@ Status: stack items 1-5 agreed by Ty; items 6-8 follow from his standards (ACX s
- (C) One command does a whole book: `python3 _pipeline/cli.py process <pdf>`. It fails with exit code 1 and a clear message if any step or any ACX check fails. Warnings are logged, there is no per-book approval gate. Re-running skips audio that already exists unless the script or voice settings changed or `--force` is given. - (C) One command does a whole book: `python3 _pipeline/cli.py process <pdf>`. It fails with exit code 1 and a clear message if any step or any ACX check fails. Warnings are logged, there is no per-book approval gate. Re-running skips audio that already exists unless the script or voice settings changed or `--force` is given.
- (C) One book at a time (workflow concurrency group). A failed run commits nothing and leaves the PDF in `_incoming/`. The commit-back is a single commit marked `[skip ci]` that also removes the PDF from `_incoming/`, so it cannot start another run. - (C) One book at a time (workflow concurrency group). A failed run commits nothing and leaves the PDF in `_incoming/`. The commit-back is a single commit marked `[skip ci]` that also removes the PDF from `_incoming/`, so it cannot start another run.
- (C) The voice endpoint is a setting (`voice.endpoint`, env `AUDIOBOOK_VOICE_ENDPOINT`, repo variable `AUDIOBOOK_VOICE_ENDPOINT`), default in CI `http://192.168.1.202:8090/tts`. Locked voice settings are unchanged. Never publish anything outside the repo. - (C) The voice endpoint is a setting (`voice.endpoint`, env `AUDIOBOOK_VOICE_ENDPOINT`, repo variable `AUDIOBOOK_VOICE_ENDPOINT`), default in CI `http://192.168.1.202:8090/tts`. Locked voice settings are unchanged. Never publish anything outside the repo.
## Metadata must never fail a drop, and links can be dropped (2026-10-18, Ty)
- (C) Missing title/author never stops a run (run 191 failed on a scanned PDF with no "by" line and no PDF metadata). Order is deterministic and logged: sidecar .json, then PDF Title / a "By Name" line on the first pages (OCR for scanned first pages) / PDF Author, then a name under the title, then the file name. No author = "Unknown" (folder `unknown`) with a warning; no title = cleaned file name. book.json records the source of each value (`metadata_sources`). Code: `_pipeline/meta.py`.
- (C) Ty can drop `_incoming/<anything>.url` (or `.txt`) holding one http(s) address of a PDF (Windows `URL=` shortcut also read; arxiv.org/abs/<id> is rewritten to the PDF). The job downloads it (curl, redirects, time and size limits, must be a real PDF), stores it as the book's source PDF, records `source_url` in book.json, removes the link file in the same atomic commit-back, and commits nothing on failure. Code: `_pipeline/fetch.py`.