2026.08 Prayers for Daily Life
2
.gitignore
vendored
@ -7,6 +7,8 @@
|
||||
*.out
|
||||
*.fls
|
||||
*.fdb_latexmk
|
||||
*.zip
|
||||
*.swp
|
||||
|
||||
*.tar
|
||||
|
||||
|
||||
BIN
2026.05-SGH-02/latex/SGH2.epub
Normal file
9
2026.05-SGH-02/latex/epub.yaml
Normal file
@ -0,0 +1,9 @@
|
||||
title: "Stories from GrailHeart — Volume 2"
|
||||
author: "William"
|
||||
lang: en-US
|
||||
|
||||
toc: true
|
||||
toc-title: "Contents"
|
||||
|
||||
rights: "Copyright © 2026 William"
|
||||
|
||||
33
2026.05-SGH-02/latex/latex2epub.sh
Executable file
@ -0,0 +1,33 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
INPUT="$1"
|
||||
|
||||
if [ -z "$INPUT" ]; then
|
||||
echo "Usage: $0 main.tex"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f "$INPUT" ]; then
|
||||
echo "ERROR: File not found: $INPUT"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
BASENAME="${INPUT%.tex}"
|
||||
OUTPUT="${BASENAME}.epub"
|
||||
|
||||
echo "Converting:"
|
||||
echo " $INPUT"
|
||||
echo "to:"
|
||||
echo " $OUTPUT"
|
||||
|
||||
pandoc \
|
||||
--from=latex \
|
||||
--to=epub3 \
|
||||
--metadata-file=epub.yaml \
|
||||
--resource-path=".:$(dirname "$INPUT")" \
|
||||
"$INPUT" \
|
||||
-o "$OUTPUT"
|
||||
|
||||
echo "Done: $OUTPUT"
|
||||
BIN
2026.08-PrayersForDailyLife/art/99449d83-303c-4dee-9310-5cfef8d9e764.png
Executable file
|
After Width: | Height: | Size: 2.4 MiB |
BIN
2026.08-PrayersForDailyLife/art/A+/1-Hook.af
Executable file
BIN
2026.08-PrayersForDailyLife/art/A+/1-Hook.jpg
Executable file
|
After Width: | Height: | Size: 294 KiB |
BIN
2026.08-PrayersForDailyLife/art/A+/1.af
Executable file
BIN
2026.08-PrayersForDailyLife/art/A+/1.jpg
Executable file
|
After Width: | Height: | Size: 597 KiB |
BIN
2026.08-PrayersForDailyLife/art/A+/2-Value.af
Executable file
BIN
2026.08-PrayersForDailyLife/art/A+/2-Value.jpg
Executable file
|
After Width: | Height: | Size: 267 KiB |
BIN
2026.08-PrayersForDailyLife/art/A+/2.af
Executable file
BIN
2026.08-PrayersForDailyLife/art/A+/2.jpg
Executable file
|
After Width: | Height: | Size: 492 KiB |
BIN
2026.08-PrayersForDailyLife/art/A+/3-Proof.af
Executable file
BIN
2026.08-PrayersForDailyLife/art/A+/3-Proof.jpg
Executable file
|
After Width: | Height: | Size: 1.3 MiB |
BIN
2026.08-PrayersForDailyLife/art/A+/3.af
Executable file
BIN
2026.08-PrayersForDailyLife/art/A+/3.jpg
Executable file
|
After Width: | Height: | Size: 511 KiB |
BIN
2026.08-PrayersForDailyLife/art/A+/4-Close.af
Executable file
BIN
2026.08-PrayersForDailyLife/art/A+/4-Close.jpg
Executable file
|
After Width: | Height: | Size: 327 KiB |
BIN
2026.08-PrayersForDailyLife/art/A+/4.af
Executable file
BIN
2026.08-PrayersForDailyLife/art/A+/4.jpg
Executable file
|
After Width: | Height: | Size: 544 KiB |
BIN
2026.08-PrayersForDailyLife/art/A+/4741efbf-20d9-4133-91d3-5b291f3b4949.png
Executable file
|
After Width: | Height: | Size: 2.4 MiB |
BIN
2026.08-PrayersForDailyLife/art/Back-2026.09.16-1230.af
Executable file
BIN
2026.08-PrayersForDailyLife/art/Back-2026.09.16-1230.jpg
Executable file
|
After Width: | Height: | Size: 3.0 MiB |
BIN
2026.08-PrayersForDailyLife/art/BackSpineFront-2026.09.16-1230.af
Executable file
BIN
2026.08-PrayersForDailyLife/art/BackSpineFront-Cover-2026.09.16-1230.af
Executable file
BIN
2026.08-PrayersForDailyLife/art/BackSpineFront-Cover-2026.09.16-1230.jpg
Executable file
|
After Width: | Height: | Size: 2.5 MiB |
BIN
2026.08-PrayersForDailyLife/art/BackSpineFront-NoTitle.png
Executable file
|
After Width: | Height: | Size: 2.1 MiB |
BIN
2026.08-PrayersForDailyLife/art/BackSpineFront.af
Executable file
BIN
2026.08-PrayersForDailyLife/art/BackSpineFront.pdf
Executable file
BIN
2026.08-PrayersForDailyLife/art/BackSpineFront.png
Executable file
|
After Width: | Height: | Size: 2.2 MiB |
BIN
2026.08-PrayersForDailyLife/art/Barcode_979-8-17-335708-3.png
Executable file
|
After Width: | Height: | Size: 20 KiB |
BIN
2026.08-PrayersForDailyLife/art/Front-2026.09.16-1230.jpg
Executable file
|
After Width: | Height: | Size: 2.5 MiB |
BIN
2026.08-PrayersForDailyLife/art/Frontr-2026.09.16-1230.af
Executable file
BIN
2026.08-PrayersForDailyLife/art/Interior-FearOfNothavingEnough.af
Executable file
BIN
2026.08-PrayersForDailyLife/art/Interior-FearOfNothavingEnough.jpg
Executable file
|
After Width: | Height: | Size: 501 KiB |
BIN
2026.08-PrayersForDailyLife/art/Interior-SeekingGodBeforeBigDecisions.af
Executable file
BIN
2026.08-PrayersForDailyLife/art/Interior-SeekingGodBeforeBigDecisions.jpg
Executable file
|
After Width: | Height: | Size: 632 KiB |
BIN
2026.08-PrayersForDailyLife/art/Interior-StarsOnAClearNight.jpg
Executable file
|
After Width: | Height: | Size: 517 KiB |
|
After Width: | Height: | Size: 658 KiB |
@ -0,0 +1,9 @@
|
||||
*How to use your template*
|
||||
|
||||
1. Open the PDF or PNG file for the Paperback Book Cover Template in your image editing software.
|
||||
2. Create a new layer in your image editing software. This layer will serve as the design layer.
|
||||
3. Design your cover in the design layer, using the template PDF or PNG file as the guide layer. The artwork should extend to the outside edge of the template's pink zone to ensure a white border will not exist within the printed work. Do not move the guide layer, as it is properly aligned for our printing specifications.
|
||||
4. Ensure text and/or images that are intended to be read do not appear in the pink zones of the template.
|
||||
5. The barcode area is indicated in yellow on the template. Do not place important images or text intended to be read in the barcode location. We suggest filling in this area with your background color or design. KDP will automatically generate a barcode representing your title’s ISBN when printing copies of your book.
|
||||
6. Once your design is complete, you will need to turn off the guide layer so that it is not printed on your final product or rejected during the review process. If you are unable to turn off the guide layer, then you will need to format the artwork so that it completely covers the guide layer.
|
||||
7. Flatten all layers, save the file as a press quality PDF with CMYK color profile, and upload the file via KDP.
|
||||
BIN
2026.08-PrayersForDailyLife/art/_BackTitleBlurb.af
Executable file
BIN
2026.08-PrayersForDailyLife/art/_FrontTitle.af
Executable file
BIN
2026.08-PrayersForDailyLife/art/_ZecharaihPress.af
Executable file
BIN
2026.08-PrayersForDailyLife/art/_ZechariahPress.png
Executable file
|
After Width: | Height: | Size: 81 KiB |
BIN
2026.08-PrayersForDailyLife/art/back.png
Executable file
|
After Width: | Height: | Size: 2.0 MiB |
BIN
2026.08-PrayersForDailyLife/art/cover.png
Executable file
|
After Width: | Height: | Size: 2.0 MiB |
BIN
2026.08-PrayersForDailyLife/art/prayers101_qr.pdf
Normal file → Executable file
BIN
2026.08-PrayersForDailyLife/latex/PrayersForDailyLife.epub
Normal file
680
2026.08-PrayersForDailyLife/latex/generate_epub.py
Executable file
@ -0,0 +1,680 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
generate_epub.py
|
||||
|
||||
Converts the same category-coded .txt files used by generate_latex.py
|
||||
(CODE-CCC.VV.txt, one occasion per file) directly into a single valid
|
||||
EPUB3 file, suitable for upload to KDP as the Kindle edition.
|
||||
|
||||
This does NOT go through the LaTeX/PDF pipeline -- print-specific
|
||||
formatting (drop caps, lettrine, fixed page breaks, hard \\ line breaks
|
||||
mid-stanza) doesn't translate to Kindle's reflowable text, where the
|
||||
reader controls font size and line spacing. Instead, this script parses
|
||||
the .txt files directly (same parser shape as generate_latex.py) and
|
||||
emits clean, semantic XHTML -- one file per category chapter, containing
|
||||
all of that chapter's prayers -- with a proper EPUB3 nav document AND a
|
||||
legacy NCX (older Kindle "Go To" menus still expect NCX; including both
|
||||
costs nothing and avoids navigation complaints).
|
||||
|
||||
Within each prayer, stanza breaks (blank lines in the source) become
|
||||
<p> boundaries; single line breaks WITHIN a stanza become <br/>, so the
|
||||
poem's line structure is preserved without relying on print-only
|
||||
line-break macros.
|
||||
|
||||
Usage:
|
||||
python generate_epub.py txt output.epub \\
|
||||
--title "Prayers for Daily Life" \\
|
||||
--subtitle "101 Devotional Prayers for Every Occasion" \\
|
||||
--author "George Marin" \\
|
||||
--publisher "Zechariah Press" \\
|
||||
--cover cover.jpg \\
|
||||
--uuid urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||
|
||||
If --uuid isn't given, a random one is generated each run -- fine for
|
||||
testing, but pick ONE fixed UUID for the real book and pass it every
|
||||
time (this is the file's permanent identity; changing it between
|
||||
uploads can confuse KDP/retailers into treating updates as a new book).
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import html
|
||||
import re
|
||||
import sys
|
||||
import uuid
|
||||
import zipfile
|
||||
from pathlib import Path
|
||||
|
||||
from categories import CATEGORIES, VALID_CODES, category_name
|
||||
|
||||
# --- Parsing (same shape as generate_latex.py) ------------------------------
|
||||
|
||||
HEADER_RE = re.compile(
|
||||
r"^(?P<ref>##\s*\S+)[ \t]*\n"
|
||||
r">(?!>)[ \t]*(?P<title>[^\n]*)\n"
|
||||
r">>[ \t]*(?P<quote>[^\n]*)\n"
|
||||
)
|
||||
OCCASION_LINE_RE = re.compile(r"(?m)^Occasion:[ \t]*(?P<text>.+)$")
|
||||
FILENAME_RE = re.compile(r"^(?P<code>[A-Z]+)-(?P<chapter>\d{3})\.(?P<verse>\d{2,3})(?:-[a-z])?\.txt$")
|
||||
REF_RE = re.compile(r"^(?P<chapter>\d+):(?P<verse>\d+)")
|
||||
|
||||
|
||||
def strip_comment_lines(text: str) -> str:
|
||||
lines = text.split("\n")
|
||||
out = []
|
||||
in_block = False
|
||||
for ln in lines:
|
||||
stripped = ln.strip()
|
||||
if not in_block and stripped == "%v":
|
||||
in_block = True
|
||||
continue
|
||||
if in_block:
|
||||
if stripped == "%^":
|
||||
in_block = False
|
||||
continue
|
||||
if ln.lstrip().startswith("%"):
|
||||
continue
|
||||
out.append(ln)
|
||||
return "\n".join(out)
|
||||
|
||||
|
||||
def parse_ref(ref_line: str) -> str:
|
||||
return ref_line.lstrip("#").strip()
|
||||
|
||||
|
||||
def ref_sort_key(ref: str):
|
||||
m = REF_RE.match(ref)
|
||||
if not m:
|
||||
return (9999, 9999)
|
||||
return (int(m.group("chapter")), int(m.group("verse")))
|
||||
|
||||
|
||||
def parse_file(text: str):
|
||||
text = strip_comment_lines(text)
|
||||
stripped = text.lstrip("\n")
|
||||
m = HEADER_RE.match(stripped)
|
||||
if not m:
|
||||
return None
|
||||
ref = parse_ref(m.group("ref"))
|
||||
title = m.group("title").strip()
|
||||
quote = m.group("quote").strip()
|
||||
body = text[m.end():]
|
||||
matches = list(OCCASION_LINE_RE.finditer(body))
|
||||
if len(matches) != 1:
|
||||
return None
|
||||
mo = matches[0]
|
||||
occasion = mo.group("text").strip()
|
||||
prayer_text = body[mo.end():].strip()
|
||||
if not prayer_text:
|
||||
return None
|
||||
return {"ref": ref, "title": title, "quote": quote, "occasion": occasion, "text": prayer_text}
|
||||
|
||||
|
||||
_MINOR_WORDS = {
|
||||
"a", "an", "and", "as", "at", "but", "by", "en", "for", "if", "in",
|
||||
"nor", "of", "on", "or", "per", "the", "to", "v", "via", "vs",
|
||||
}
|
||||
|
||||
|
||||
def _title_case_word(word: str) -> str:
|
||||
i = 0
|
||||
while i < len(word) and not word[i].isalpha():
|
||||
i += 1
|
||||
if i >= len(word):
|
||||
return word
|
||||
return word[:i] + word[i].upper() + word[i + 1:].lower()
|
||||
|
||||
|
||||
def title_case(text: str) -> str:
|
||||
words = text.split(" ")
|
||||
out = []
|
||||
for idx, w in enumerate(words):
|
||||
bare = re.sub(r"[^a-zA-Z']", "", w).lower()
|
||||
if 0 < idx < len(words) - 1 and bare in _MINOR_WORDS:
|
||||
out.append(w.lower())
|
||||
else:
|
||||
out.append(_title_case_word(w))
|
||||
return " ".join(out)
|
||||
|
||||
|
||||
# --- HTML rendering ----------------------------------------------------------
|
||||
|
||||
def esc(text: str) -> str:
|
||||
return html.escape(text, quote=False)
|
||||
|
||||
|
||||
def convert_latex_typography(text: str) -> str:
|
||||
"""Converts this project's LaTeX-only typographic conventions into
|
||||
real Unicode characters, since none of them mean anything to an
|
||||
EPUB reader: "---" (em dash ligature) -> em dash; ``...'' (curly
|
||||
quote ligature) -> real curly quotes."""
|
||||
text = text.replace("---", "\u2014")
|
||||
text = text.replace("``", "\u201c").replace("''", "\u201d")
|
||||
return text
|
||||
|
||||
|
||||
def render_foreword_from_latex(tex_text: str) -> str:
|
||||
"""Parses an ACTUAL template_forward.tex file (not a separate plain-text
|
||||
copy -- single source of truth, same file that feeds the print
|
||||
pipeline) into foreword HTML. Handles this project's specific
|
||||
foreword conventions:
|
||||
- \\chapter*{...} and \\addcontentsline{...} lines are dropped (the
|
||||
EPUB foreword gets its own <h1> here instead)
|
||||
- \\medskip and \\bigskip mark paragraph breaks
|
||||
- \\noindent is stripped
|
||||
- wrapped lines within one paragraph are joined with spaces (the
|
||||
LaTeX source hard-wraps for readability; those line breaks
|
||||
aren't meaningful the way a prayer's stanza line breaks are)
|
||||
- \\textit{...} becomes <em>...</em>
|
||||
- "---" / ``...'' typography converted via convert_latex_typography()
|
||||
"""
|
||||
text = tex_text
|
||||
text = re.sub(r"\\chapter\*\{[^}]*\}", "", text)
|
||||
text = re.sub(r"\\addcontentsline\{[^}]*\}\{[^}]*\}\{[^}]*\}", "", text)
|
||||
|
||||
# \medskip and \bigskip both mark a paragraph break
|
||||
chunks = re.split(r"\\(?:med|big)skip", text)
|
||||
paragraphs = []
|
||||
for chunk in chunks:
|
||||
chunk = chunk.replace("\\noindent", "")
|
||||
# collapse hard-wrapped source lines into one flowing paragraph
|
||||
joined = " ".join(ln.strip() for ln in chunk.split("\n") if ln.strip())
|
||||
if not joined:
|
||||
continue
|
||||
joined = convert_latex_typography(joined)
|
||||
# \textit{...} -> <em>...</em>, done via sentinel markers so the
|
||||
# em-tags themselves survive the HTML-escape step untouched
|
||||
joined = re.sub(r"\\textit\{([^}]*)\}", lambda m: "\uE000" + m.group(1) + "\uE001", joined)
|
||||
joined = esc(joined)
|
||||
joined = joined.replace("\uE000", "<em>").replace("\uE001", "</em>")
|
||||
paragraphs.append(f"<p>{joined}</p>")
|
||||
return "\n".join(paragraphs)
|
||||
|
||||
|
||||
def render_prayer_html(entry: dict, anchor_id: str) -> str:
|
||||
"""One prayer as semantic XHTML: heading, verse blockquote, body
|
||||
paragraphs (stanza = <p>, in-stanza line break = <br/>).
|
||||
|
||||
A dagger (†) follows the final line (always "Amen.") of every
|
||||
prayer, matching the print edition's "Amen.\\enspace$\\dagger$"
|
||||
convention.
|
||||
|
||||
See convert_latex_typography() -- the source files use LaTeX-only
|
||||
ligature conventions for em dashes and curly quotes that need
|
||||
converting to real Unicode characters outside the LaTeX pipeline."""
|
||||
stanzas = [b.strip() for b in re.split(r"\n\s*\n", entry["text"].strip()) if b.strip()]
|
||||
para_html = []
|
||||
for i, stanza in enumerate(stanzas):
|
||||
lines = [esc(convert_latex_typography(ln.strip())) for ln in stanza.split("\n") if ln.strip()]
|
||||
joined = "<br/>\n".join(lines)
|
||||
if i == len(stanzas) - 1:
|
||||
joined += " †"
|
||||
para_html.append(f"<p>{joined}</p>")
|
||||
body = "\n".join(para_html)
|
||||
|
||||
title = esc(title_case(entry["occasion"]))
|
||||
quote = esc(convert_latex_typography(entry["quote"]))
|
||||
ref = esc(entry["ref"])
|
||||
|
||||
return f"""<section class="prayer" id="{anchor_id}">
|
||||
<h3>{title}</h3>
|
||||
<blockquote class="verse"><p>{quote} <span class="ref">(Ps. {ref})</span></p></blockquote>
|
||||
{body}
|
||||
</section>"""
|
||||
|
||||
|
||||
def render_chapter_xhtml(code: str, entries: list, title_prefix: str, flourish_img: str | None = None):
|
||||
"""Returns (html, toc_items) where toc_items is a list of
|
||||
(anchor_id, prayer_title) pairs -- used by the caller to build the
|
||||
nested chapter->prayer TOC (nav.xhtml, toc.ncx, AND the visible
|
||||
in-book toc.xhtml page all share this same structure).
|
||||
|
||||
flourish_img, if given, is the filename (already placed under
|
||||
OEBPS/images/) of a decorative divider shown under the chapter
|
||||
title -- same graphic as the print edition's chapter openers."""
|
||||
name = esc(category_name(code))
|
||||
sections = []
|
||||
toc_items = []
|
||||
for i, e in enumerate(entries):
|
||||
anchor = f"{code.lower()}-{i+1:03d}"
|
||||
sections.append(render_prayer_html(e, anchor))
|
||||
toc_items.append((anchor, title_case(e["occasion"])))
|
||||
body = "\n\n".join(sections)
|
||||
flourish_html = ""
|
||||
if flourish_img:
|
||||
flourish_html = f'<p class="flourish"><img src="../images/{esc(flourish_img)}" alt="" role="presentation"/></p>'
|
||||
html_out = f"""<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:epub="http://www.idpf.org/2007/ops" lang="en">
|
||||
<head>
|
||||
<title>{name}</title>
|
||||
<link rel="stylesheet" type="text/css" href="../css/style.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<h1>{name}</h1>
|
||||
{flourish_html}
|
||||
{body}
|
||||
</body>
|
||||
</html>"""
|
||||
return html_out, toc_items
|
||||
|
||||
|
||||
def render_simple_xhtml(title: str, body_html: str) -> str:
|
||||
return f"""<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:epub="http://www.idpf.org/2007/ops" lang="en">
|
||||
<head>
|
||||
<title>{esc(title)}</title>
|
||||
<link rel="stylesheet" type="text/css" href="../css/style.css"/>
|
||||
</head>
|
||||
<body>
|
||||
{body_html}
|
||||
</body>
|
||||
</html>"""
|
||||
|
||||
|
||||
DEFAULT_CSS = """
|
||||
body { font-family: serif; margin: 1em; line-height: 1.4; }
|
||||
h1 { text-align: center; margin-top: 1.5em; margin-bottom: 1em; page-break-before: always; }
|
||||
h2 { text-align: center; }
|
||||
h3 { margin-top: 2em; page-break-before: always; }
|
||||
.prayer { margin-bottom: 2em; }
|
||||
.verse { font-style: italic; margin: 1em 2em; }
|
||||
.verse .ref { font-style: normal; }
|
||||
.titlepage { text-align: center; margin-top: 3em; }
|
||||
.titlepage h1 { page-break-before: avoid; font-size: 1.8em; margin-bottom: 0.2em; }
|
||||
.titlepage .subtitle { font-size: 1.1em; margin-bottom: 2em; }
|
||||
.titlepage .author { font-size: 1.2em; margin-top: 2em; }
|
||||
.copyright { font-size: 0.85em; }
|
||||
.foreword p { margin-bottom: 1em; }
|
||||
.center { text-align: center; }
|
||||
|
||||
/* Chapter-opening divider graphic, sized relative to text width so it
|
||||
scales with the reader's font size / screen, not a fixed pixel size. */
|
||||
p.flourish { text-align: center; margin: 0.5em 0 1.5em 0; }
|
||||
p.flourish img { width: 30%; max-width: 220px; height: auto; }
|
||||
"""
|
||||
|
||||
# --- EPUB packaging -----------------------------------------------------------
|
||||
|
||||
CONTAINER_XML = """<?xml version="1.0" encoding="UTF-8"?>
|
||||
<container version="1.0" xmlns="urn:oasis:names:tc:opendocument:xmlns:container">
|
||||
<rootfiles>
|
||||
<rootfile full-path="OEBPS/content.opf" media-type="application/oebps-package+xml"/>
|
||||
</rootfiles>
|
||||
</container>
|
||||
"""
|
||||
|
||||
|
||||
def _manifest_item_line(iid: str, href: str, mtype: str, is_nav: bool) -> str:
|
||||
# Kept as a plain function (not inlined in the f-string below) because
|
||||
# a backslash-escaped quote inside an f-string's {} expression part is
|
||||
# only legal on Python 3.12+ (PEP 701) -- this needs to run on older
|
||||
# Python too.
|
||||
nav_attr = ' properties="nav"' if is_nav else ""
|
||||
return f' <item id="{iid}" href="{href}" media-type="{mtype}"{nav_attr}/>'
|
||||
|
||||
|
||||
def build_opf(book_uuid: str, title: str, subtitle: str, author: str, publisher: str,
|
||||
manifest_items: list, spine_ids: list, cover_id: str | None,
|
||||
toc_page_href: str | None) -> str:
|
||||
meta_cover = f'<meta name="cover" content="{cover_id}"/>' if cover_id else ""
|
||||
manifest = "\n".join(_manifest_item_line(iid, href, mtype, is_nav) for iid, href, mtype, is_nav in manifest_items)
|
||||
spine = "\n".join(f' <itemref idref="{sid}"/>' for sid in spine_ids)
|
||||
full_title = f"{title}: {subtitle}" if subtitle else title
|
||||
# <guide> is EPUB2-era, but Kindle's conversion pipeline and older
|
||||
# reading apps still use it to find the table of contents -- costs
|
||||
# nothing to include alongside the EPUB3 nav doc.
|
||||
guide = ""
|
||||
if toc_page_href:
|
||||
guide = f""" <guide>
|
||||
<reference type="toc" title="Table of Contents" href="{toc_page_href}"/>
|
||||
</guide>
|
||||
"""
|
||||
return f"""<?xml version="1.0" encoding="UTF-8"?>
|
||||
<package xmlns="http://www.idpf.org/2007/opf" version="3.0" unique-identifier="BookId">
|
||||
<metadata xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<dc:identifier id="BookId">{esc(book_uuid)}</dc:identifier>
|
||||
<dc:title>{esc(full_title)}</dc:title>
|
||||
<dc:creator>{esc(author)}</dc:creator>
|
||||
<dc:publisher>{esc(publisher)}</dc:publisher>
|
||||
<dc:language>en</dc:language>
|
||||
<meta property="dcterms:modified">2026-01-01T00:00:00Z</meta>
|
||||
{meta_cover}
|
||||
</metadata>
|
||||
<manifest>
|
||||
<item id="css" href="css/style.css" media-type="text/css"/>
|
||||
{manifest}
|
||||
</manifest>
|
||||
<spine toc="ncx">
|
||||
{spine}
|
||||
</spine>
|
||||
{guide}</package>
|
||||
"""
|
||||
|
||||
|
||||
def build_nav(title: str, toc_entries: list) -> str:
|
||||
"""toc_entries: list of dicts {href, label, children: [(href, label), ...]}."""
|
||||
items = []
|
||||
for entry in toc_entries:
|
||||
li = f' <li><a href="{entry["href"]}">{esc(entry["label"])}</a>'
|
||||
if entry["children"]:
|
||||
sub = "\n".join(f' <li><a href="{h}">{esc(l)}</a></li>' for h, l in entry["children"])
|
||||
li += f'\n <ol>\n{sub}\n </ol>\n '
|
||||
li += "</li>"
|
||||
items.append(li)
|
||||
items_str = "\n".join(items)
|
||||
return f"""<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:epub="http://www.idpf.org/2007/ops" lang="en">
|
||||
<head><title>{esc(title)}</title></head>
|
||||
<body>
|
||||
<nav epub:type="toc" id="toc">
|
||||
<h1>Contents</h1>
|
||||
<ol>
|
||||
{items_str}
|
||||
</ol>
|
||||
</nav>
|
||||
</body>
|
||||
</html>"""
|
||||
|
||||
|
||||
def render_psalm_index_xhtml(title: str, all_entries: list) -> str:
|
||||
"""all_entries: list of (ref, href_with_anchor, prayer_title), already
|
||||
sorted by ref_sort_key. Unlike the print index (ref -> page number,
|
||||
meaningless in reflowable text with no fixed pages), each entry here
|
||||
is a direct clickable link to that prayer -- arguably MORE useful
|
||||
than the print version, since it's one tap instead of a page flip.
|
||||
href_with_anchor is relative to OEBPS/text/ (where this file lives),
|
||||
same convention as render_toc_page_xhtml."""
|
||||
items = "\n".join(
|
||||
f' <li><a href="{href}">{esc(ref)}</a> — {esc(prayer_title)}</li>'
|
||||
for ref, href, prayer_title in all_entries
|
||||
)
|
||||
body = f'<div class="psalm-index"><h1>Index of Psalm References</h1><ol>\n{items}\n</ol></div>'
|
||||
return render_simple_xhtml(title, body)
|
||||
|
||||
|
||||
def render_toc_page_xhtml(title: str, toc_entries: list) -> str:
|
||||
"""A real, visible in-book Contents page (unlike nav.xhtml, which
|
||||
most reading apps treat as sidebar-menu metadata, not a page you
|
||||
actually read through). This is what was missing -- KDP/Kindle
|
||||
conversion and many EPUB readers expect an actual TOC page in the
|
||||
reading order, not just the EPUB3 nav doc.
|
||||
|
||||
IMPORTANT: this file itself lives at OEBPS/text/toc.xhtml, alongside
|
||||
the chapter files -- so unlike nav.xhtml (which lives at the OEBPS/
|
||||
root and needs "text/..." prefixed hrefs), links here must be
|
||||
relative to the text/ directory, i.e. with that prefix stripped."""
|
||||
def strip_prefix(href: str) -> str:
|
||||
return href[len("text/"):] if href.startswith("text/") else href
|
||||
|
||||
items = []
|
||||
for entry in toc_entries:
|
||||
href = strip_prefix(entry["href"])
|
||||
li = f' <li><a href="{href}">{esc(entry["label"])}</a>'
|
||||
if entry["children"]:
|
||||
sub = "\n".join(f' <li><a href="{strip_prefix(h)}">{esc(l)}</a></li>' for h, l in entry["children"])
|
||||
li += f'\n <ol>\n{sub}\n </ol>\n '
|
||||
li += "</li>"
|
||||
items.append(li)
|
||||
items_str = "\n".join(items)
|
||||
body = f'<div class="toc-page"><h1>Contents</h1><ol>\n{items_str}\n</ol></div>'
|
||||
return render_simple_xhtml(title, body)
|
||||
|
||||
|
||||
def build_ncx(book_uuid: str, title: str, toc_entries: list) -> str:
|
||||
points = []
|
||||
counter = [0]
|
||||
|
||||
def next_order():
|
||||
counter[0] += 1
|
||||
return counter[0]
|
||||
|
||||
for entry in toc_entries:
|
||||
parent_order = next_order()
|
||||
child_points = []
|
||||
for h, l in entry["children"]:
|
||||
child_order = next_order()
|
||||
child_points.append(f""" <navPoint id="navPoint-{child_order}" playOrder="{child_order}">
|
||||
<navLabel><text>{esc(l)}</text></navLabel>
|
||||
<content src="{h}"/>
|
||||
</navPoint>""")
|
||||
child_str = "\n".join(child_points)
|
||||
points.append(f""" <navPoint id="navPoint-{parent_order}" playOrder="{parent_order}">
|
||||
<navLabel><text>{esc(entry['label'])}</text></navLabel>
|
||||
<content src="{entry['href']}"/>
|
||||
{child_str}
|
||||
</navPoint>""")
|
||||
points_str = "\n".join(points)
|
||||
return f"""<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ncx xmlns="http://www.daisy.org/z3986/2005/ncx/" version="2005-1">
|
||||
<head>
|
||||
<meta name="dtb:uid" content="{esc(book_uuid)}"/>
|
||||
</head>
|
||||
<docTitle><text>{esc(title)}</text></docTitle>
|
||||
<navMap>
|
||||
{points_str}
|
||||
</navMap>
|
||||
</ncx>
|
||||
"""
|
||||
|
||||
|
||||
def write_epub(out_path: Path, files: dict, image_paths: list):
|
||||
"""files: dict of archive-path -> str content (text files) OR bytes.
|
||||
image_paths: list of local Path objects to copy in under
|
||||
OEBPS/images/ (cover, flourish, etc.) -- their manifest entries are
|
||||
added by the caller; this just physically copies the bytes in.
|
||||
mimetype MUST be first and MUST be stored (not deflated)."""
|
||||
if out_path.exists():
|
||||
out_path.unlink()
|
||||
with zipfile.ZipFile(out_path, "w") as z:
|
||||
z.writestr("mimetype", "application/epub+zip", compress_type=zipfile.ZIP_STORED)
|
||||
for path, content in files.items():
|
||||
data = content if isinstance(content, bytes) else content.encode("utf-8")
|
||||
z.writestr(path, data, compress_type=zipfile.ZIP_DEFLATED)
|
||||
for img_path in image_paths:
|
||||
z.write(img_path, f"OEBPS/images/{img_path.name}", compress_type=zipfile.ZIP_DEFLATED)
|
||||
|
||||
|
||||
# --- Main ---------------------------------------------------------------------
|
||||
|
||||
def main():
|
||||
ap = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
|
||||
ap.add_argument("txt_dir", type=Path)
|
||||
ap.add_argument("output_epub", type=Path)
|
||||
ap.add_argument("--title", default="Prayers for Daily Life")
|
||||
ap.add_argument("--subtitle", default="101 Devotional Prayers for Every Occasion")
|
||||
ap.add_argument("--author", default="George Marin")
|
||||
ap.add_argument("--publisher", default="Zechariah Press")
|
||||
ap.add_argument("--cover", type=Path, default=None, help="Cover image (jpg/png). Strongly recommended for KDP.")
|
||||
ap.add_argument("--flourish", type=Path, default=None, help="Optional decorative divider image (jpg/png) shown under each chapter title -- same graphic as the print edition's chapter openers, if you want it.")
|
||||
ap.add_argument("--foreword", type=Path, default=None, help="Your actual template_forward.tex file -- parsed directly (paragraph breaks on \\medskip/\\bigskip, \\textit{} to italics, etc.), not a separate plain-text copy.")
|
||||
ap.add_argument("--review-url", default=None, help="If given, adds a back-matter review-request page with a clickable link to this URL (NOT a QR code -- pointless in an ebook, since the reader's already on the device).")
|
||||
ap.add_argument("--no-psalm-index", action="store_true", help="Omit the back-matter Index of Psalm References (on by default). Unlike the print version, this is a page of CLICKABLE LINKS, not page numbers -- reflowable text has no fixed pages to index.")
|
||||
ap.add_argument("--uuid", default=None, help="Fixed book UUID (e.g. urn:uuid:...). Random if omitted -- fine for testing, but pin one for the real release.")
|
||||
ap.add_argument("--category-order", default=None, help="Comma-separated category codes, e.g. WON,WWF,CRI,...")
|
||||
args = ap.parse_args()
|
||||
|
||||
# Fail loudly and immediately if an optional file path was actually
|
||||
# GIVEN but doesn't resolve -- silently skipping it (the old
|
||||
# behavior) is exactly the kind of mistake that ships a KDP EPUB
|
||||
# with no embedded cover and nobody notices until much later.
|
||||
for flag_name, path in [
|
||||
("--cover", args.cover),
|
||||
("--flourish", args.flourish),
|
||||
("--foreword", args.foreword),
|
||||
]:
|
||||
if path is not None and not path.exists():
|
||||
sys.exit(f"{flag_name} was given as {path!s}, but that file doesn't exist. Fix the path or drop the flag.")
|
||||
|
||||
book_uuid = args.uuid or f"urn:uuid:{uuid.uuid4()}"
|
||||
|
||||
order = args.category_order.split(",") if args.category_order else list(CATEGORIES.keys())
|
||||
for c in order:
|
||||
if c not in VALID_CODES:
|
||||
sys.exit(f"Unknown category code in --category-order: {c}")
|
||||
|
||||
txt_files = sorted(args.txt_dir.glob("*.txt"))
|
||||
by_category: dict[str, list] = {c: [] for c in order}
|
||||
skipped = []
|
||||
for path in txt_files:
|
||||
m = FILENAME_RE.match(path.name)
|
||||
if not m or m.group("code") not in VALID_CODES:
|
||||
continue
|
||||
parsed = parse_file(path.read_text(encoding="utf-8"))
|
||||
if parsed is None:
|
||||
skipped.append(path.name)
|
||||
continue
|
||||
code = m.group("code")
|
||||
if code not in by_category:
|
||||
by_category[code] = []
|
||||
by_category[code].append(parsed)
|
||||
|
||||
if skipped:
|
||||
print(f"Skipped {len(skipped)} file(s) that didn't parse:")
|
||||
for s in skipped:
|
||||
print(f" {s}")
|
||||
|
||||
for code in by_category:
|
||||
by_category[code].sort(key=lambda e: ref_sort_key(e["ref"]))
|
||||
|
||||
total = sum(len(v) for v in by_category.values())
|
||||
print(f"Building EPUB from {total} entries across {sum(1 for v in by_category.values() if v)} categories.")
|
||||
|
||||
# --- Assemble files ---
|
||||
files: dict[str, object] = {}
|
||||
files["META-INF/container.xml"] = CONTAINER_XML
|
||||
files["OEBPS/css/style.css"] = DEFAULT_CSS
|
||||
|
||||
manifest_items = [] # (id, href, media-type, is_nav)
|
||||
spine_ids = []
|
||||
toc_entries = [] # list of {href, label, children: [(href#anchor, label), ...]}
|
||||
|
||||
# Title page
|
||||
title_html = f"""<div class="titlepage">
|
||||
<h1>{esc(args.title)}</h1>
|
||||
<p class="subtitle">{esc(args.subtitle)}</p>
|
||||
<p class="author">{esc(args.author)}</p>
|
||||
</div>"""
|
||||
files["OEBPS/text/titlepage.xhtml"] = render_simple_xhtml(args.title, title_html)
|
||||
manifest_items.append(("titlepage", "text/titlepage.xhtml", "application/xhtml+xml", False))
|
||||
spine_ids.append("titlepage")
|
||||
|
||||
# Copyright page
|
||||
copyright_html = f"""<div class="copyright">
|
||||
<p>{esc(args.title)}: {esc(args.subtitle)}</p>
|
||||
<p>Copyright © 2026. All rights reserved.</p>
|
||||
<p>Published by {esc(args.publisher)}</p>
|
||||
</div>"""
|
||||
files["OEBPS/text/copyright.xhtml"] = render_simple_xhtml("Copyright", copyright_html)
|
||||
manifest_items.append(("copyright", "text/copyright.xhtml", "application/xhtml+xml", False))
|
||||
spine_ids.append("copyright")
|
||||
|
||||
# Table of Contents -- a REAL visible page in the reading order, not just
|
||||
# the EPUB3 nav.xhtml (which most reading apps only use for their own
|
||||
# sidebar menu, not as an actual page). Placed here as a spine_ids
|
||||
# placeholder; the id "toc-page" is inserted once its file is written
|
||||
# below, once we know the full nested structure -- so reserve its
|
||||
# position in the spine now, fill in content after the loop.
|
||||
TOC_PAGE_POS = len(spine_ids)
|
||||
spine_ids.append("toc-page") # placeholder, replaced below once content is built
|
||||
|
||||
# Foreword (optional) -- parsed directly from the real template_forward.tex
|
||||
if args.foreword: # existence already validated above
|
||||
fw_html = "<h1>Foreword</h1>\n" + render_foreword_from_latex(args.foreword.read_text(encoding="utf-8"))
|
||||
files["OEBPS/text/foreword.xhtml"] = render_simple_xhtml("Foreword", f'<div class="foreword">{fw_html}</div>')
|
||||
manifest_items.append(("foreword", "text/foreword.xhtml", "application/xhtml+xml", False))
|
||||
spine_ids.append("foreword")
|
||||
toc_entries.append({"href": "text/foreword.xhtml", "label": "Foreword", "children": []})
|
||||
|
||||
# One XHTML file per category chapter, plus its nested prayer-level
|
||||
# TOC entries (anchor links within that chapter's file)
|
||||
for code in order:
|
||||
entries = by_category.get(code, [])
|
||||
if not entries:
|
||||
continue
|
||||
chapter_html, prayer_toc_items = render_chapter_xhtml(
|
||||
code, entries, args.title,
|
||||
flourish_img=args.flourish.name if args.flourish else None, # existence already validated above
|
||||
)
|
||||
fname = f"{code.lower()}.xhtml"
|
||||
files[f"OEBPS/text/{fname}"] = chapter_html
|
||||
cid = f"chap-{code.lower()}"
|
||||
manifest_items.append((cid, f"text/{fname}", "application/xhtml+xml", False))
|
||||
spine_ids.append(cid)
|
||||
children = [(f"text/{fname}#{anchor}", label) for anchor, label in prayer_toc_items]
|
||||
toc_entries.append({"href": f"text/{fname}", "label": category_name(code), "children": children})
|
||||
|
||||
# Review request (optional) -- a real hyperlink, not a QR code; see
|
||||
# --review-url help text for why a QR code doesn't make sense here.
|
||||
if args.review_url:
|
||||
review_html = f"""<div class="center">
|
||||
<h2>Did this book meet you somewhere?</h2>
|
||||
<p>If it did, a review helps the next reader find their way here too.</p>
|
||||
<p><a href="{esc(args.review_url)}">{esc(args.review_url)}</a></p>
|
||||
</div>"""
|
||||
files["OEBPS/text/review.xhtml"] = render_simple_xhtml("A Request", review_html)
|
||||
manifest_items.append(("review", "text/review.xhtml", "application/xhtml+xml", False))
|
||||
spine_ids.append("review")
|
||||
|
||||
# Index of Psalm References (optional, on by default) -- flat list
|
||||
# across ALL categories, sorted by verse reference, each entry
|
||||
# linking directly to its prayer. Built here (after every chapter's
|
||||
# anchors are known) rather than during the per-category loop above,
|
||||
# since it needs the complete cross-category picture.
|
||||
if not args.no_psalm_index:
|
||||
all_entries = []
|
||||
for code in order:
|
||||
for i, e in enumerate(by_category.get(code, [])):
|
||||
anchor = f"{code.lower()}-{i+1:03d}"
|
||||
href = f"{code.lower()}.xhtml#{anchor}"
|
||||
all_entries.append((e["ref"], href, title_case(e["occasion"])))
|
||||
all_entries.sort(key=lambda t: ref_sort_key(t[0]))
|
||||
files["OEBPS/text/psalm-index.xhtml"] = render_psalm_index_xhtml("Index of Psalm References", all_entries)
|
||||
manifest_items.append(("psalm-index", "text/psalm-index.xhtml", "application/xhtml+xml", False))
|
||||
spine_ids.append("psalm-index")
|
||||
toc_entries.append({"href": "text/psalm-index.xhtml", "label": "Index of Psalm References", "children": []})
|
||||
|
||||
# Now that toc_entries is fully built, write the actual TOC page and
|
||||
# fill in the spine placeholder reserved above.
|
||||
files["OEBPS/text/toc.xhtml"] = render_toc_page_xhtml("Contents", toc_entries)
|
||||
manifest_items.append(("toc-page", "text/toc.xhtml", "application/xhtml+xml", False))
|
||||
spine_ids[TOC_PAGE_POS] = "toc-page"
|
||||
|
||||
# Cover
|
||||
cover_id = None
|
||||
image_paths = [] # local files to physically copy into OEBPS/images/
|
||||
if args.cover: # existence already validated above
|
||||
image_paths.append(args.cover)
|
||||
media_type = "image/jpeg" if args.cover.suffix.lower() in (".jpg", ".jpeg") else "image/png"
|
||||
cover_id = "cover-image"
|
||||
manifest_items.append((cover_id, f"images/{args.cover.name}", media_type, False))
|
||||
cover_xhtml = f'<div class="center"><img src="../images/{esc(args.cover.name)}" alt="Cover" style="max-width:100%;"/></div>'
|
||||
files["OEBPS/text/cover.xhtml"] = render_simple_xhtml("Cover", cover_xhtml)
|
||||
manifest_items.append(("cover-page", "text/cover.xhtml", "application/xhtml+xml", False))
|
||||
spine_ids.insert(0, "cover-page")
|
||||
|
||||
if args.flourish: # existence already validated above
|
||||
image_paths.append(args.flourish)
|
||||
media_type = "image/jpeg" if args.flourish.suffix.lower() in (".jpg", ".jpeg") else "image/png"
|
||||
manifest_items.append(("flourish-image", f"images/{args.flourish.name}", media_type, False))
|
||||
|
||||
# Nav + NCX -- both reference the SAME nested toc_entries as the
|
||||
# visible toc.xhtml page above, so the reader-UI sidebar and the
|
||||
# in-book Contents page always agree.
|
||||
manifest_items.append(("nav", "nav.xhtml", "application/xhtml+xml", True))
|
||||
manifest_items.append(("ncx", "toc.ncx", "application/x-dtbncx+xml", False))
|
||||
files["OEBPS/nav.xhtml"] = build_nav(args.title, toc_entries)
|
||||
files["OEBPS/toc.ncx"] = build_ncx(book_uuid, args.title, toc_entries)
|
||||
|
||||
files["OEBPS/content.opf"] = build_opf(
|
||||
book_uuid, args.title, args.subtitle, args.author, args.publisher,
|
||||
manifest_items, spine_ids, cover_id, toc_page_href="text/toc.xhtml",
|
||||
)
|
||||
|
||||
write_epub(args.output_epub, files, image_paths)
|
||||
print(f"Wrote {args.output_epub} ({total} prayers, {sum(1 for v in by_category.values() if v)} chapters)")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@ -147,7 +147,7 @@ No permission is required for its use.
|
||||
|
||||
\noindent Published by Zechariah Press
|
||||
|
||||
\noindent ISBN: 000-0-000000-00-0 % TODO: replace with the assigned ISBN before publication
|
||||
\noindent ISBN: 979-8-1733570-08-3 % 000-0-000000-00-0
|
||||
|
||||
\medskip
|
||||
\noindent First Edition
|
||||
|
||||
10
2026.08-PrayersForDailyLife/latex/make-epub.sh
Executable file
@ -0,0 +1,10 @@
|
||||
python3 generate_epub.py ../txt PrayersForDailyLife.epub \
|
||||
--title "Prayers for Daily Life" \
|
||||
--subtitle "101 Devotional Prayers for Every Occasion" \
|
||||
--author "George Marin" \
|
||||
--publisher "Zechariah Press" \
|
||||
--cover ../art/BackSpineFront-Cover-2026.09.16-1230.jpg \
|
||||
--foreword ./template-foreward.tex \
|
||||
--review-url "https://zechariahpress.com/q/PrayersForDailyLife" \
|
||||
--uuid "1460ac0b-4f40-4645-b12b-2c78aee89d34" \
|
||||
--flourish ../art/o01.png
|
||||
5
2026.08-PrayersForDailyLife/latex/make.sh → 2026.08-PrayersForDailyLife/latex/make-pdf.sh
Normal file → Executable file
@ -4,11 +4,12 @@ set -e
|
||||
rm -f main.aux main.idx main.ilg main.ind main.ind main.log main.pdf main.toc $DEPOT/main.pdf
|
||||
for p in CON CRI DRY GRA GUI LOS MIL REL TMP WON WWF
|
||||
do
|
||||
rm $p*.tex
|
||||
rm -f $p*.tex
|
||||
done
|
||||
python3 generate_latex.py ../txt . --template template-prayer.tex --main-template template-main.tex
|
||||
pdflatex main
|
||||
makeindex main
|
||||
pdflatex main
|
||||
pdflatex main
|
||||
cp main.pdf "$DEPOT/main-$(date +%Y.%m.%d-%H%M).pdf"
|
||||
|
||||
cp main.pdf "Prayers-$(date +%Y.%m.%d-%H%M).pdf"
|
||||
@ -4,24 +4,24 @@
|
||||
\noindent I didn't set out to write a hundred and one prayers.
|
||||
I set out to write the ones I needed and couldn't find ---
|
||||
short enough to pray before the day got away,
|
||||
plain enough to skip the churchier language.
|
||||
plain enough to skip churchy language.
|
||||
|
||||
\medskip
|
||||
\noindent It didn't take long to notice a pattern:
|
||||
that every prayer
|
||||
every prayer
|
||||
rhymed with something a psalmist had already said three thousand years ago.
|
||||
Weariness, wonder, gratitude, grief --- none of it is new.
|
||||
|
||||
\medskip
|
||||
\noindent This book borrows their voice.
|
||||
Each prayer opens with a verse from the Psalms and stays close to it,
|
||||
but with present-day concerns --- a hospital wristband, a gurney, plastic bins after a storm.
|
||||
but with present-day concerns --- a hospital wristband, plastic bins after a storm.
|
||||
A prayer too general, ``Lord, help me in my trouble,'' rarely moves anyone;
|
||||
it asks for nothing you can picture.
|
||||
it asks for nothing you can wrap your hands around.
|
||||
But one too specific runs a different risk: what if your trouble doesn't look like mine?
|
||||
|
||||
\medskip
|
||||
\noindent So hold these loosely. Think of each one less as a script
|
||||
\noindent So hold these loosely. Think of them less as a script
|
||||
and more as an aperture --- a way of opening your imagination onto something
|
||||
you already recognize. Let your words take over where mine leave off.
|
||||
|
||||
@ -33,7 +33,7 @@ since it's what most of us are used to.
|
||||
|
||||
\medskip
|
||||
\noindent Wherever you are today --- weary, waiting, grateful, undone ---
|
||||
my prayer is that you'll find something here that meets you there.
|
||||
my prayer is that you'll find something here that meets you where you are.
|
||||
|
||||
\bigskip
|
||||
\noindent \textit{George Marin}
|
||||
@ -147,7 +147,7 @@ No permission is required for its use.
|
||||
|
||||
\noindent Published by Zechariah Press
|
||||
|
||||
\noindent ISBN: 000-0-000000-00-0 % TODO: replace with the assigned ISBN before publication
|
||||
\noindent ISBN: 979-8-1733570-08-3 % 000-0-000000-00-0
|
||||
|
||||
\medskip
|
||||
\noindent First Edition
|
||||
|
||||
@ -13,5 +13,10 @@ find their way here too.}
|
||||
|
||||
\vspace{1em}
|
||||
{\small zechariahpress.com/reviews/PrayersForDailyLife}
|
||||
|
||||
\vspace{1.5em}
|
||||
{\itshape \large Thank you.}
|
||||
|
||||
\end{center}
|
||||
|
||||
\vspace*{\fill}
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
> My soul longs, and even faints for the courts of the LORD
|
||||
>> My soul longs, and even faints for the courts of the LORD; my heart and my flesh cry out for the living God.
|
||||
|
||||
Occasion: Restless after getting what you wanted
|
||||
Occasion: Restless after getting what I wanted
|
||||
|
||||
Lord, I got the thing I asked for,
|
||||
and nothing changed.
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
## 143:8
|
||||
%% 4
|
||||
> Your Lovingkindness in the Morning
|
||||
>> Cause me to hear your lovingkindness in the morning, for I trust in you. Cause me to know the way in which I should walk, for I lift up my soul to you.
|
||||
>> Cause me to hear your lovingkindness in the morning, for I trust in you.
|
||||
|
||||
Occasion: Praying first thing
|
||||
|
||||
@ -11,16 +11,12 @@ before I speak to anyone else,
|
||||
Lord, let me speak with You.
|
||||
|
||||
I am here, though part of me is still waking,
|
||||
and part of me has already begun
|
||||
to carry the weight of the day.
|
||||
Yesterday is not entirely gone.
|
||||
Today is already asking things of me.
|
||||
and today is already asking things of me.
|
||||
|
||||
Let Your kindness be the first thing I hear this morning.
|
||||
Let Your lovingkindness be the first thing I hear this morning.
|
||||
|
||||
Teach me to bring You my soul
|
||||
before I hand this day to habit,
|
||||
hurry,
|
||||
before I hand this day to habit, hurry,
|
||||
or whatever shouts the loudest.
|
||||
|
||||
One thought follows another,
|
||||
@ -30,16 +26,14 @@ where I am going
|
||||
or who I am becoming along the way.
|
||||
|
||||
So make this first turning toward You plain.
|
||||
A chair.
|
||||
A breath.
|
||||
A breath. A whisper.
|
||||
A few honest words.
|
||||
|
||||
I don't need to sound wise ---
|
||||
as if You didn't already know me.
|
||||
I don't need the whole way mapped ---
|
||||
one step is what You've promised.
|
||||
Only show me how to walk faithfully
|
||||
into the hours before me,
|
||||
one step is all You've promised.
|
||||
Only show me how to walk faithfully into the hours before me,
|
||||
and give me grace enough
|
||||
for the next thing.
|
||||
|
||||
@ -48,4 +42,4 @@ be first.
|
||||
Before the screen lights up,
|
||||
be first.
|
||||
|
||||
Amen.
|
||||
Amen.
|
||||
@ -14,7 +14,7 @@ trying to secure tomorrow with my own hands.
|
||||
One unanswered question becomes ten,
|
||||
and soon I am living inside a future
|
||||
that has not even arrived.
|
||||
And likjely never will.
|
||||
And likely never will.
|
||||
I am tired of carrying it,
|
||||
but I am afraid of what will happen if I let it go.
|
||||
|
||||
|
||||
@ -6,7 +6,6 @@
|
||||
Occasion: When I'm grateful but don't quite know how to say it
|
||||
|
||||
Lord, thank You.
|
||||
|
||||
Saying that seems too small,
|
||||
but it's what I have.
|
||||
|
||||
@ -43,4 +42,4 @@ these inadequate words will have to suffice:
|
||||
|
||||
Thank You.
|
||||
|
||||
Amen.
|
||||
Amen.
|
||||
|
||||
@ -6,7 +6,6 @@
|
||||
Occasion: When I've had a good day
|
||||
|
||||
Lord, today was good.
|
||||
|
||||
Nothing spectacular.
|
||||
No sea parted.
|
||||
No mountain moved.
|
||||
@ -42,4 +41,4 @@ I was here for it.
|
||||
And I am glad.
|
||||
And grateful.
|
||||
|
||||
Amen.
|
||||
Amen.
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
> Teach Us To Count Our Days
|
||||
>> So teach us to count our days, that we may gain a heart of wisdom.
|
||||
|
||||
Occasion: Choosing how to spend your time
|
||||
Occasion: Choosing how to spend my time
|
||||
|
||||
There are too many tasks in front of me, Lord ---
|
||||
the message to answer,
|
||||
|
||||
@ -6,7 +6,6 @@
|
||||
Occasion: Miscarriage
|
||||
|
||||
Lord, You knit together what I never got to hold.
|
||||
|
||||
I don't have a photograph.
|
||||
I don't have a name everyone else got to use.
|
||||
Just a due date I still know by heart,
|
||||
@ -34,4 +33,4 @@ be someone You carry still.
|
||||
|
||||
Hold what I never got to hold.
|
||||
|
||||
Amen.
|
||||
Amen.
|
||||
|
||||
@ -39,3 +39,6 @@ one ordinary moment at a time.
|
||||
Be the first guest in this house,
|
||||
the one who never leaves,
|
||||
the one who makes it a home.
|
||||
|
||||
Amen.
|
||||
|
||||
|
||||
@ -6,7 +6,6 @@
|
||||
Occasion: When I need to forgive
|
||||
|
||||
Lord, I know I need to forgive.
|
||||
|
||||
I also know I cannot make the hurt disappear
|
||||
by deciding that I should.
|
||||
|
||||
|
||||
@ -6,7 +6,6 @@
|
||||
Occasion: When I need courage for an ordinary conversation
|
||||
|
||||
Lord, I need to say something.
|
||||
|
||||
It is not a speech.
|
||||
No crowd is waiting.
|
||||
The world will go on afterward.
|
||||
@ -41,4 +40,4 @@ be acceptable to You.
|
||||
Help me open my mouth
|
||||
and begin.
|
||||
|
||||
Amen.
|
||||
Amen.
|
||||
|
||||
@ -6,7 +6,6 @@
|
||||
Occasion: When I can't let something go
|
||||
|
||||
Lord, here it is again.
|
||||
|
||||
The memory.
|
||||
The conversation.
|
||||
The mistake.
|
||||
@ -44,4 +43,4 @@ I am putting it down again.
|
||||
And if I pick it up tomorrow,
|
||||
I will bring it back again.
|
||||
|
||||
Amen.
|
||||
Amen.
|
||||
|
||||
@ -6,7 +6,6 @@
|
||||
Occasion: When I don't want to do what needs doing
|
||||
|
||||
Lord, I know what needs doing.
|
||||
|
||||
I simply don't want to do it.
|
||||
|
||||
I'd rather postpone it,
|
||||
@ -42,4 +41,4 @@ This is today's work.
|
||||
|
||||
Establish it.
|
||||
|
||||
Amen.
|
||||
Amen.
|
||||
|
||||
@ -6,7 +6,6 @@
|
||||
Occasion: When I'm disappointed in myself
|
||||
|
||||
Lord, I expected better of myself.
|
||||
|
||||
I thought I would handle this differently.
|
||||
I thought I had grown past this.
|
||||
I thought by now I would be wiser,
|
||||
@ -42,4 +41,4 @@ You have not mistaken me
|
||||
for someone already finished.
|
||||
Let's begin again.
|
||||
|
||||
Amen
|
||||
Amen.
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
|
||||
Occasion: Caring for the natural world
|
||||
|
||||
MMorning light on the leaves, Lord.
|
||||
Morning light on the leaves, Lord.
|
||||
Water running over stone.
|
||||
The smell of rain on warm earth.
|
||||
This world is precious,
|
||||
@ -45,4 +45,4 @@ Keep me in that light,
|
||||
attentive and humble,
|
||||
careful with what is Yours.
|
||||
|
||||
Amen.
|
||||
Amen.
|
||||
|
||||
@ -6,10 +6,8 @@
|
||||
Occasion: When I'm bone tired
|
||||
|
||||
Lord, I'm bone tired.
|
||||
|
||||
Nothing terrible has happened.
|
||||
No crisis to solve.
|
||||
|
||||
I've simply reached the end
|
||||
of what I have for today.
|
||||
|
||||
|
||||
@ -5,7 +5,6 @@
|
||||
Occasion: When I can't stop worrying
|
||||
|
||||
Lord, my mind will not leave this alone.
|
||||
|
||||
I turn it over,
|
||||
then turn it over again,
|
||||
looking for something I missed,
|
||||
@ -32,4 +31,4 @@ Still my soul beside You,
|
||||
like a child who no longer needs to understand ---
|
||||
all that matters is where home is.
|
||||
|
||||
Amen.
|
||||
Amen.
|
||||
|
||||
122
2026.08-PrayersForDailyLife/verbiage/TOC.txt
Executable file
@ -0,0 +1,122 @@
|
||||
Wonder & Thanksgiving
|
||||
* Feeling small in a big world
|
||||
* After a close call
|
||||
* Thanking God for creation
|
||||
* Caring for the natural world
|
||||
* Wonder at how I'm made
|
||||
* The stars on a clear night
|
||||
* Wonder at absolutely everything
|
||||
|
||||
Weariness, Worry & Fear
|
||||
* Waiting for the right season
|
||||
* Trouble falling asleep
|
||||
* Waking up worried
|
||||
* Slow recovery from illness
|
||||
* Fearing joy won't last
|
||||
* Before speaking in public
|
||||
* When I'm bone tired
|
||||
* Fear of not having enough
|
||||
* After losing a job
|
||||
* When I have to wait
|
||||
* When I can't stop worrying
|
||||
* During a lonely season
|
||||
|
||||
Guidance \& Decisions
|
||||
* Bringing dreams before God
|
||||
* Making a big move
|
||||
* Facing an important morning
|
||||
* Seeking God before decisions
|
||||
* When I reach for the wrong refuge
|
||||
* Making the most of today
|
||||
* Stress from too many decisions
|
||||
* Choosing how to spend your time
|
||||
* Taking one step at a time
|
||||
* Needing moral clarity
|
||||
|
||||
Crisis \& Emergency
|
||||
* Waiting for test results
|
||||
* When panic takes over
|
||||
* Before a big surgery
|
||||
* Bad news from far away
|
||||
* Bad news from the doctor
|
||||
* Starting over after disaster
|
||||
* After hearing bad news
|
||||
* Facing the end of life
|
||||
|
||||
Loss
|
||||
* A loss of something important
|
||||
* Loss of a pet
|
||||
* Grieving a broken family
|
||||
* Loss of a child
|
||||
* Miscarriage
|
||||
* Loss of a friend
|
||||
* Loss of parents
|
||||
* Loss of a spouse
|
||||
* Grieving a suicide
|
||||
|
||||
Milestones
|
||||
* Starting a new job
|
||||
* Moving into a new home
|
||||
* Graduation
|
||||
* Wedding
|
||||
* The arrival of a new child
|
||||
* The arrival of a new grandchild
|
||||
* Retirement
|
||||
|
||||
Temptation \& Self-Examination
|
||||
* Envy over someone else's success
|
||||
* After a failure
|
||||
* Letting go of control
|
||||
* Asking forgiveness for hurtful words
|
||||
* When I can't let something go
|
||||
* When shame keeps me away
|
||||
* When I don't want to do what needs doing
|
||||
* Wanting wholehearted worship
|
||||
* Confessing hidden wrongdoing
|
||||
* When I'm disappointed in myself
|
||||
* Wanting to break old habits
|
||||
* When my motives are mixed
|
||||
|
||||
Spiritual Dryness \& Discontent
|
||||
* A distracted heart
|
||||
* Coming back after drifting
|
||||
* When today feels wasted
|
||||
* Restless after getting what you wanted
|
||||
* Discouraged by slow growth
|
||||
* Inner turmoil
|
||||
* When God's goodness feels distant
|
||||
* When gratitude feels hard
|
||||
* Praying first thing
|
||||
|
||||
Relationships
|
||||
* After being let down
|
||||
* After hurting someone deeply
|
||||
* When you have no one to talk to
|
||||
* Teaching a child about God
|
||||
* Children afraid of the dark
|
||||
* When I need to forgive
|
||||
* Building a marriage
|
||||
* When I need courage for an ordinary conversation
|
||||
|
||||
Conflicts
|
||||
* Joining in cruel jokes
|
||||
* Stress over unfair treatment
|
||||
* When I'm angry with someone I love
|
||||
* Walking into a hard meeting
|
||||
* Trouble that follows you home
|
||||
* A church split healing
|
||||
|
||||
Gratitude
|
||||
* Learning to trust God's provision
|
||||
* Thanking God for answered prayer
|
||||
* Coming out of a hard season
|
||||
* Seeking contentment in God
|
||||
* Giving thanks for enough
|
||||
* Thankfulness for this morning
|
||||
* Waking up grateful
|
||||
* Singing with joy again
|
||||
* Remembering past help
|
||||
* Staying faithful in old age
|
||||
* When blessings feel ordinary
|
||||
* When I'm grateful but don't quite know how to say it
|
||||
* When I've had a good day
|
||||