Lectionary to HTML Tool

By crone.us, 15 March, 2026

I decided on a structure, for better or worse, that uses the lectionary readings from Vanderbilt.  However it is unpleasant to set up, and probably unpleasant to use, and it is what I came up with in ten minutes at Hibachi 88.  If you have a suggestion for a better structure feel free to offer it, and maybe come up with a converter.  In the meantime, I had Gemini spin up this Python script to take a tab-delimited set of lectionary readings and output the basic structure; if there are alternate readings they nest in brackets.  Thus one of my sets for Easter is "[Acts 2:1-21    Numbers 11:24-30]    Psalm 104:24-34, 35b    [1 Corinthians 12:3b-13    Acts 2:1-21]    [John 20:19-23    John 7:37-39]" which then spews out some HTML source I feed into the article body.

Python follows, no license because there is no copyright because it is AI generated.  If you want to modify it I can put it up on github, but given its triviality I am just leaving it here for now.

import urllib.parse
import re

def clean_reference_for_url(reference):
    """
    Cleans the reference for the Bible Gateway URL:
    1. Removes lowercase letters from verse numbers (1a -> 1).
    2. Replaces semicolons with commas for better BG parsing.
    """
    # Remove lowercase letters preceded by a digit
    ref = re.sub(r'(?<=\d)[a-z]', '', reference)
    # Replace semicolon with comma for the URL string
    ref = ref.replace(';', ',')
    return ref

def generate_bible_html(reference, indent_level=0):
    """Generates the details/summary HTML block with 4-space indentation."""
    base_indent = "    " * indent_level
    inner_indent = "    " * (indent_level + 1)

    url_ref = clean_reference_for_url(reference)
    encoded_ref = urllib.parse.quote(url_ref)
    url = f"https://www.biblegateway.com/passage/?search={encoded_ref}&amp;version=NRSVUE"

    html = (
        f"{base_indent}<details>\n"
        f"{inner_indent}<summary><a href=\"{url}\">{reference}</a></summary>\n"
        f"{inner_indent}<p>\n"
        f"{inner_indent}    &nbsp;\n"
        f"{inner_indent}</p>\n"
        f"{base_indent}</details>"
    )
    return html

def process_set(input_text):
    # Split the main set only by tabs.
    # The regex \t(?![^\[]*\]) ignores tabs inside brackets [].
    groups = re.split(r'\t(?![^\[]*\])', input_text.strip())

    groups = [g for g in groups if g]

    for group in groups:
        if group.startswith('[') and group.endswith(']'):
            # Split internal refs by tab only
            inner_content = group[1:-1].strip()
            refs = [r.strip() for r in inner_content.split('\t') if r.strip()]

            print("<ul>")
            for r in refs:
                print("    <li>")
                print(generate_bible_html(r, indent_level=2))
                print("    </li>")
            print("</ul>")
        else:
            print(generate_bible_html(group, indent_level=0))


def main():
    print("Paste your references. Use TABS to separate the 4 groups.")
    print("Brackets [] indicate a group of multiple references (also tab-separated).")
    print("Example: Heb 4:14-16; 5:7-9\t[John 1:1\tJohn 1:14]\tEx 12:1-4, (5-10)")
    print("Press Ctrl+C to exit.\n")

    try:
        while True:
            # Note: In some terminals, you may need to paste the tab character
            # or the terminal might convert it to spaces.
            user_input = input("Set: ")
            if not user_input.strip():
                continue
            print("\n" + "="*10 + " OUTPUT " + "="*10)
            process_set(user_input)
            print("="*28 + "\n")
    except KeyboardInterrupt:
        print("\nExiting.")

if __name__ == "__main__":
    main()