diff options
| author | Danilo M. <danix@danix.xyz> | 2026-10-05 11:54:56 +0200 |
|---|---|---|
| committer | Danilo M. <danix@danix.xyz> | 2026-10-05 11:54:56 +0200 |
| commit | 20e515b79796789a835a76aaf5656f5370764968 (patch) | |
| tree | ef2c4ff9bf2b139f59bfcd936ae9668b9aae039f | |
| parent | e3e08870d4d120145d5667a16602fc3a15167b76 (diff) | |
| download | fanfictioner-20e515b79796789a835a76aaf5656f5370764968.tar.gz fanfictioner-20e515b79796789a835a76aaf5656f5370764968.zip | |
Drop chapter_title from the story frontmatter
It only replaced the plan.md heading, which nothing downstream reads.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
| -rw-r--r-- | README.md | 5 | ||||
| -rw-r--r-- | docs/superpowers/specs/2026-10-04-fanfictioner-design.md | 5 | ||||
| -rwxr-xr-x | fanfictioner | 12 |
3 files changed, 9 insertions, 13 deletions
@@ -22,12 +22,11 @@ instead of letting Gemma invent them; every key is optional: series: A new life book: Life as Daniel chapter: 1 - chapter_title: Intro title: Meet Daniel --- -`series` and `book` name the library folders, `title` is the cover lettering, -`chapter_title` heads plan.md. With `chapter`, pages are saved as +`series` and `book` name the library folders, `title` is the lettering on the +chapter's page 1. With `chapter`, pages are saved as `01-001.png`, `01-002.png`, so every chapter of a book (one story file each) reads as one continuous book in book-reader. These values always override what Gemma writes in plan.md. diff --git a/docs/superpowers/specs/2026-10-04-fanfictioner-design.md b/docs/superpowers/specs/2026-10-04-fanfictioner-design.md index d762243..9ebcb8f 100644 --- a/docs/superpowers/specs/2026-10-04-fanfictioner-design.md +++ b/docs/superpowers/specs/2026-10-04-fanfictioner-design.md @@ -56,10 +56,9 @@ read from `~/.config/book-reader.conf` (shell `KEY="value"` lines). Series and Book come from plan.md. story.md may start with a `---` frontmatter (`series`, `book`, `chapter`, -`chapter_title`, `title`, all optional). The script writes these into plan.md +`title`, all optional). The script writes these into plan.md after every draft and revision and whenever story.md changes, overriding -Gemma: Series/Book/Chapter header lines, the `# ` heading, and page 1's -`Title:`. plan.json is rebuilt when plan.md or story.md is newer than it. +Gemma: Series/Book/Chapter header lines and page 1's `Title:`. plan.json is rebuilt when plan.md or story.md is newer than it. Resume is derived from disk, no state file: a character with `refs/<Name>.png` is skipped; a page whose `NNN.png` exists in the library is skipped. diff --git a/fanfictioner b/fanfictioner index 267b9dc..010b521 100755 --- a/fanfictioner +++ b/fanfictioner @@ -137,10 +137,8 @@ def apply_front(md, meta): if not (drop and re.match(r"[-*\s]*\**(%s)\**:" % "|".join(drop), x.strip()))] top = next((i for i, x in enumerate(lines) if x.startswith("# ")), None) if top is None: - lines.insert(0, "# " + (meta.get("chapter_title") or meta.get("title") or "Untitled")) + lines.insert(0, "# " + meta.get("title", "Untitled")) top = 0 - elif meta.get("chapter_title"): - lines[top] = "# " + meta["chapter_title"] lines[top + 1:top + 1] = [f"{k}: {meta[k.lower()]}" for k in keys] if meta.get("title"): p1 = next((i for i, x in enumerate(lines) if re.match(r"###\s+1\.", x.strip())), None) @@ -656,19 +654,19 @@ def selftest(): parse_plan(SAMPLE_PLAN.replace("wide shot, portrait", "wide shot"))) meta, body = parse_front('---\nseries: A new life\nbook: "Life as Daniel"\nchapter: 1\n' - 'chapter_title: Intro\ntitle: Meet Daniel\n---\nThis is the story.\n') + 'title: Meet Daniel\n---\nThis is the story.\n') assert meta == {"series": "A new life", "book": "Life as Daniel", "chapter": "1", - "chapter_title": "Intro", "title": "Meet Daniel"} and body == "This is the story.\n", meta + "title": "Meet Daniel"} and body == "This is the story.\n", meta assert parse_front("no frontmatter") == ({}, "no frontmatter") forced = apply_front(SAMPLE_PLAN.replace("Framing: wide shot, eye level, landscape", "Framing: wide shot, eye level, landscape\nTitle: Gemma Title"), meta) assert apply_front(forced, meta) == forced assert apply_front(SAMPLE_PLAN, {}) == SAMPLE_PLAN fp = parse_plan(forced) - assert (fp["title"], fp["series"], fp["book"], fp["chapter"]) == ("Intro", "A new life", "Life as Daniel", "1"), fp + assert (fp["title"], fp["series"], fp["book"], fp["chapter"]) == ("Rooftop", "A new life", "Life as Daniel", "1"), fp assert fp["pages"][0]["lettering"] == "Meet Daniel" and fp["pages"][1]["lettering"] == "", fp["pages"] assert fp["pages"][0]["framing"] == "wide shot, eye level, landscape" and validate_plan(fp) == [] - assert forced.count("Title:") == 1 and forced.startswith("# Intro\nSeries: A new life\nBook: Life as Daniel\n" + assert forced.count("Title:") == 1 and forced.startswith("# Rooftop\nSeries: A new life\nBook: Life as Daniel\n" "Chapter: 1\nStyle:"), forced assert build_json(fp)["chapter"] == 1 and build_json(plan)["chapter"] is None assert 'Chapter must be a number, not "one"' in validate_plan( |
