#!/usr/bin/env python3 """ Convert sajeevavahini Zefania XML bible -> per-book .bin/.idx format for BibleVerse app. Usage: python tools/convert_bible.py --src "World English Bible.xml" --dst assets/bible # or auto-download: python tools/convert_bible.py --download WEB --dst assets/bible """ import argparse, os, sys, json, struct, pathlib, urllib.request, xml.etree.ElementTree as ET # mapping for --download shortcut to raw urls DL_MAP = { "WEB": "https://raw.githubusercontent.com/sajeevavahini/bibles/main/World%20English%20Bible.xml", "KJV": "https://raw.githubusercontent.com/sajeevavahini/bibles/main/King%20James%20Version.xml", "ASV": "https://raw.githubusercontent.com/sajeevavahini/bibles/main/American%20Standard%20Version%20(1901).xml", } def download(url, dst_path): print(f"Downloading {url} -> {dst_path}") urllib.request.urlretrieve(url, dst_path) print(f" done {os.path.getsize(dst_path)} bytes") def parse_and_write(src_xml, dst_dir): os.makedirs(dst_dir, exist_ok=True) print(f"Parsing {src_xml} ...") books_data = {} # bnum -> {bname, chapters: {cnum: [(vnum,text)]}} cur_bnum = 0; cur_bname=""; cur_cnum=0 # iterparse for low memory ctx = ET.iterparse(src_xml, events=("start","end")) for event, elem in ctx: if event=="start": if elem.tag=="BIBLEBOOK": cur_bnum=int(elem.attrib.get("bnumber","0")) cur_bname=elem.attrib.get("bname","").strip() if cur_bnum not in books_data: books_data[cur_bnum]={"bname":cur_bname, "chapters":{}} elif elem.tag=="CHAPTER": cur_cnum=int(elem.attrib.get("cnumber","0")) if cur_bnum in books_data: books_data[cur_bnum]["chapters"].setdefault(cur_cnum, []) else: if elem.tag=="VERS": vnum=int(elem.attrib.get("vnumber","0")) text=(elem.text or "").strip() if text and cur_bnum in books_data: books_data[cur_bnum]["chapters"].setdefault(cur_cnum, []).append((vnum,text)) if elem.tag in ("VERS","CHAPTER","BIBLEBOOK"): elem.clear() print(f"Found {len(books_data)} books") book_list=[] total=0 for bnum in sorted(books_data.keys()): binfo=books_data[bnum] bname=binfo["bname"] chapters=binfo["chapters"] entries=[] for cnum in sorted(chapters.keys()): for vnum, txt in sorted(chapters[cnum], key=lambda x: x[0]): entries.append((cnum,vnum,txt)) total+=len(entries) bin_path=os.path.join(dst_dir, f"{bnum:02d}.bin") idx_path=os.path.join(dst_dir, f"{bnum:02d}.idx") with open(bin_path,"wb") as bf, open(idx_path,"wb") as ix: ix.write(struct.pack("<4sHI", b'BIBK', 1, len(entries))) off=0 for cnum,vnum,txt in entries: data=txt.encode('utf-8') bf.write(data+b'\x00') ix.write(struct.pack("