From f739fc28776eff0465c2f9577b0c2e1fa3d7dea2 Mon Sep 17 00:00:00 2001 From: historia Date: Mon, 17 Aug 2026 21:22:46 -0400 Subject: feat: lorem ipsum flag --- README.md | 5 +++-- epubgen.py | 46 +++++++++++++++++++++++++++++++++++++--------- 2 files changed, 40 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 8feee2f..e34c09b 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # epubgen -Python EPUB 3.3 generator for making test files. It will pull paragraphs from a text file randomly to generate the content of the book. It also has a torture mode which randomly adds unusual characters to try to break parsers. +Python EPUB 3.3 generator for making test files. It will pull paragraphs from a text file randomly to generate the content of the book. It also has a torture mode which randomly adds unusual characters to try to break parsers. If no text file is available, it falls back to generated lorem ipsum text. ## Usage @@ -17,7 +17,8 @@ python epubgen.py -m normal -c 10 -p 5 | `-t, --title` | `The Testing EPUB` | book title | | `-a, --author` | `Test Author` | book author | | `--seed N` | random | RNG seed for reproducibility | -| `--texts FILE` | `paragraphs.txt` | one paragraph per line | +| `--texts FILE` | `paragraphs.txt` | one paragraph per line | +| `--lorem` | off | generate lorem ipsum instead of reading a file | | `--no-ncx` | off | omit the EPUB 2 NCX fallback | | `-v, --version` | | print version | diff --git a/epubgen.py b/epubgen.py index 8599b35..6b60693 100755 --- a/epubgen.py +++ b/epubgen.py @@ -33,12 +33,6 @@ VERSION = "1.0" HERE = os.path.dirname(os.path.abspath(__file__)) DEFAULT_FILE = os.path.join(HERE, "paragraphs.txt") -EMBEDDED = [ - "The wind carried the smell of rain across the valley, and the last light of the afternoon lingered on the hills.", - "She opened the ledger and began to read, though the words had been written in another hand long ago.", - "It was not the first time the old clock had stopped, but it was the first time anyone had noticed.", -] - NS = 'xmlns="http://www.w3.org/1999/xhtml" xmlns:epub="http://www.idpf.org/2007/ops"' # Hostile-but-valid Unicode (all fine in XML 1.0 / UTF-8) @@ -73,6 +67,33 @@ def first_word(texts, rng): return m.group(0) if m else "word" +# --------------------------------------------------------------------------- +# lorem ipsum generator +# --------------------------------------------------------------------------- + +LOREM_WORDS = ("lorem ipsum dolor sit amet consectetur adipiscing elit sed do " + "eiusmod tempor incididunt ut labore et dolore magna aliqua enim ad " + "minim veniam quis nostrud exercitation ullamco laboris nisi aliquip " + "ex ea commodo consequat duis aute irure in reprehenderit in voluptate " + "velit esse cillum dolore eu fugiat nulla pariatur excepteur sint " + "occaecat cupidatat non proident sunt in culpa qui officia deserunt " + "mollit anim id est laborum").split() + + +def lorem_sentence(rng, min_w=8, max_w=20): + words = [rng.choice(LOREM_WORDS) for _ in range(rng.randint(min_w, max_w))] + words[0] = words[0].capitalize() + return " ".join(words) + "." + + +def lorem_paragraph(rng, min_s=3, max_s=7): + return " ".join(lorem_sentence(rng) for _ in range(rng.randint(min_s, max_s))) + + +def lorem_texts(rng, count): + return [lorem_paragraph(rng) for _ in range(count)] + + # --------------------------------------------------------------------------- # torture helpers # --------------------------------------------------------------------------- @@ -393,14 +414,18 @@ def build_zip(out, files): "STORED" if i.compress_type == zipfile.ZIP_STORED else "DEFLATED")) -def load_texts(path): +def load_texts(path, lorem, rng, count): + if lorem: + return lorem_texts(rng, count) for p in (path, DEFAULT_FILE): if p and os.path.exists(p): with open(p, encoding="utf-8") as f: lines = [ln.strip() for ln in f if ln.strip()] if lines: return lines - return EMBEDDED + print("WARNING: no paragraph text file found; generating lorem ipsum instead", + file=sys.stderr) + return lorem_texts(rng, count) def generate(out, rng, texts, title, author, mode, nchap, npar, ncx, seed): @@ -471,6 +496,9 @@ def main(): ap.add_argument("-a", "--author", default="Test Author") ap.add_argument("--seed", type=int, default=None, help="RNG seed for reproducibility") ap.add_argument("--texts", default=None, help="file with one paragraph per line") + ap.add_argument("--lorem", action="store_true", + help="generate lorem ipsum text instead of reading a file " + "(default source: paragraphs.txt)") ap.add_argument("--no-ncx", action="store_true", help="omit the EPUB2 NCX fallback") ap.add_argument("-v", "--version", action="version", version="epubgen %s" % VERSION) args = ap.parse_args() @@ -480,7 +508,7 @@ def main(): sys.exit(1) rng = random.Random(args.seed) - texts = load_texts(args.texts) + texts = load_texts(args.texts, args.lorem, rng, args.chapters * args.paragraphs) ncx = not args.no_ncx modes = ["normal", "torture"] if args.mode == "both" else [args.mode] for mode, path in zip(modes, resolve_out_paths(args.out, args.mode)): -- cgit v1.2.3