121 lines
4.5 KiB
Python
Executable file
121 lines
4.5 KiB
Python
Executable file
#!/usr/bin/env nix-shell
|
|
#! nix-shell -i python3
|
|
#! nix-shell -p python3 python3Packages.requests
|
|
|
|
import requests
|
|
import sys
|
|
|
|
url_base = "https://bible.chandlerswift.com/api/"
|
|
# url_base = "https://bible.helloao.org/api/"
|
|
|
|
|
|
translation="BSB" # Berean Standard Bible
|
|
|
|
def help():
|
|
print(f"""
|
|
usage: {sys.argv[0]} <book> <start verse> <end verse (inclusive)>
|
|
|
|
Generates a LaTeX rendering of the given bible verses
|
|
|
|
For example, `{sys.argv[0]} Genesis 1:1 2:3`
|
|
|
|
Note that the start and end can span chapters of a book, but not books.
|
|
""")
|
|
|
|
if len(sys.argv) != 4:
|
|
help()
|
|
raise SystemExit
|
|
|
|
book = sys.argv[1]
|
|
start_chapter, start_verse = map(int, sys.argv[2].split(':'))
|
|
end_chapter, end_verse = map(int, sys.argv[3].split(':'))
|
|
|
|
books = requests.get(f"{url_base}{translation}/books.json").json()
|
|
|
|
book_id = [b for b in books['books'] if b['name'] == book or b['commonName'] == book][0]['id']
|
|
|
|
import json
|
|
|
|
def escape_latex(text):
|
|
return (text.replace('\\', r'\textbackslash{}')
|
|
.replace('&', r'\&')
|
|
.replace('%', r'\%')
|
|
.replace('$', r'\$')
|
|
.replace('#', r'\#')
|
|
.replace('_', r'\_')
|
|
.replace('{', r'\{')
|
|
.replace('}', r'\}')
|
|
.replace('~', r'\textasciitilde{}')
|
|
.replace('^', r'\textasciicircum{}'))
|
|
|
|
def render_latex(json_data):
|
|
content = json_data['chapter']['content']
|
|
footnotes = {note['noteId']: note for note in json_data['chapter'].get('footnotes', [])}
|
|
latex_lines = []
|
|
|
|
chapter_number = json_data['chapter']['number']
|
|
|
|
def render_verse_content(parts):
|
|
result = []
|
|
for part in parts:
|
|
if isinstance(part, str):
|
|
result.append(escape_latex(part))
|
|
elif isinstance(part, dict):
|
|
if 'noteId' in part:
|
|
note = footnotes.get(part['noteId'])
|
|
if note:
|
|
result.append(rf"\footnote{{{escape_latex(note['text'])}}}")
|
|
elif 'lineBreak' in part and part['lineBreak']:
|
|
# Only add \\ if already inside a paragraph
|
|
result.append(r"\newline ")
|
|
elif 'heading' in part:
|
|
result.append(rf"\textit{{{escape_latex(part['heading'])}}}")
|
|
elif 'text' in part:
|
|
result.append(escape_latex(part['text']))
|
|
return ' '.join(result)
|
|
|
|
last_seen_verse = 0 # to start; TODO: does this include extra e.g. headers sometimes?
|
|
for element in content:
|
|
if element['type'] == 'verse':
|
|
last_seen_verse = element['number']
|
|
if chapter_number == start_chapter and last_seen_verse < start_verse:
|
|
continue
|
|
if chapter_number == end_chapter and last_seen_verse >= end_verse:
|
|
break
|
|
etype = element['type']
|
|
if etype == 'heading':
|
|
heading_text = ' '.join(element['content'])
|
|
latex_lines.append(rf"\heading{{{escape_latex(heading_text)}}}")
|
|
latex_lines.append("") # Blank line to start new paragraph
|
|
elif etype == 'line_break':
|
|
# Blank line for paragraph break
|
|
latex_lines.append("")
|
|
elif etype == 'verse':
|
|
verse_number = element['number']
|
|
verse_body = render_verse_content(element['content'])
|
|
|
|
if verse_number == 1:
|
|
# First verse: show chapter number
|
|
latex_lines.append(rf"\ch{{{chapter_number}}}{verse_body}")
|
|
else:
|
|
latex_lines.append(rf"\vs{{{verse_number}}}{verse_body}")
|
|
elif etype == 'hebrew_subtitle':
|
|
subtitle_parts = []
|
|
for part in element['content']:
|
|
if isinstance(part, str):
|
|
subtitle_parts.append(escape_latex(part))
|
|
elif isinstance(part, dict):
|
|
if 'noteId' in part and part['noteId'] in footnotes:
|
|
subtitle_parts.append(rf"\footnote{{{escape_latex(footnotes[part['noteId']]['text'])}}}")
|
|
elif 'text' in part:
|
|
subtitle_parts.append(escape_latex(part['text']))
|
|
subtitle = ' '.join(subtitle_parts)
|
|
latex_lines.append(rf"\textit{{{subtitle}}}")
|
|
latex_lines.append("")
|
|
|
|
return '\n'.join(latex_lines)
|
|
|
|
for chapter in range(start_chapter, end_chapter + 1):
|
|
chapter_data = requests.get(f"{url_base}{translation}/{book_id}/{chapter}.json").json()
|
|
|
|
print(render_latex(chapter_data))
|