From 20e515b79796789a835a76aaf5656f5370764968 Mon Sep 17 00:00:00 2001 From: "Danilo M." Date: Mon, 5 Oct 2026 11:54:56 +0200 Subject: 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 --- README.md | 5 ++--- docs/superpowers/specs/2026-10-04-fanfictioner-design.md | 5 ++--- fanfictioner | 12 +++++------- 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 4ce0704..ff3cec0 100644 --- a/README.md +++ b/README.md @@ -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/.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( -- cgit v1.2.3