import os
from ebooklib import epub
from fpdf import FPDF
import markdown
class BookBuilder:
def __init__(self, title, author, description="", cover_image=None):
self.title = title
self.author = author
self.description = description
self.cover_image = cover_image
self.chapters = []
# Fetch Business Metadata from Environment
self.business_name = os.environ.get("BUSINESS_NAME", "Fair Dinkum Publishing")
self.abn = os.environ.get("BUSINESS_ABN", "63 590 716 023")
self.owner = os.environ.get("BUSINESS_OWNER", "BRETT SJOBERG")
def add_chapter(self, title, content):
self.chapters.append({"title": title, "content": content})
def generate_epub(self, output_path):
book = epub.EpubBook()
book.set_identifier(f"fdp-{abs(hash(self.title))}")
book.set_title(self.title)
book.set_language("en")
book.add_author(self.author)
book.add_metadata("DC", "publisher", self.business_name)
book.add_metadata("DC", "description", self.description)
book.add_metadata("DC", "rights", f"Copyright (c) 2026 {self.owner}. ABN: {self.abn}")
spine = ["nav"]
# Add Cover Image if provided
if self.cover_image and os.path.exists(self.cover_image):
with open(self.cover_image, 'rb') as img_file:
content = img_file.read()
img_ext = os.path.splitext(self.cover_image)[1][1:]
book.set_cover("cover.jpg", content)
# Add Copyright Page
copy_page = epub.EpubHtml(title="Copyright", file_name="copyright.xhtml", lang="en")
copy_page.content = f"""
Copyright
{self.title}
Published by {self.business_name}
Owner: {self.owner}
ABN: {self.abn}
All rights reserved. No part of this publication may be reproduced without permission.
"""
book.add_item(copy_page)
spine.append(copy_page)
for i, ch in enumerate(self.chapters):
chapter = epub.EpubHtml(title=ch["title"], file_name=f"chap_{i+1}.xhtml", lang="en")
# Convert Markdown to HTML
content_html = markdown.markdown(ch["content"])
chapter.content = f"{ch['title']}
{content_html}"
book.add_item(chapter)
spine.append(chapter)
book.add_item(epub.EpubNav())
book.add_item(epub.EpubNcx())
book.spine = spine
epub.write_epub(output_path, book, {})
return output_path
def generate_pdf(self, output_path):
pdf = FPDF()
pdf.set_auto_page_break(auto=True, margin=15)
# Title Page
pdf.add_page()
if self.cover_image and os.path.exists(self.cover_image):
# Try to fit cover image on first page
pdf.image(self.cover_image, x=10, y=10, w=190)
pdf.add_page()
pdf.set_font("Arial", "B", 24)
pdf.cell(200, 40, self.title, ln=True, align="C")
pdf.set_font("Arial", "I", 16)
pdf.cell(200, 10, f"By {self.author}", ln=True, align="C")
pdf.ln(20)
# Copyright Info
pdf.set_font("Arial", "", 10)
pdf.cell(0, 10, f"Published by {self.business_name}", ln=True, align="C")
pdf.cell(0, 10, f"ABN: {self.abn}", ln=True, align="C")
pdf.ln(20)
# Chapters
for ch in self.chapters:
pdf.add_page()
pdf.set_font("Arial", "B", 18)
pdf.cell(0, 10, ch["title"], ln=True)
pdf.ln(10)
# Use write_html to handle basic markdown-to-html conversion for FPDF
# FPDF2 supports basic HTML tags with write_html
html_content = markdown.markdown(ch["content"])
pdf.set_font("Arial", "", 12)
pdf.write_html(html_content)
# Footer on every page
pdf.set_y(-15)
pdf.set_font("Arial", "I", 8)
pdf.cell(0, 10, f"{self.business_name} - ABN {self.abn} - Page {pdf.page_no()}", align="C")
pdf.output(output_path)
return output_path
def create_ebook_files(title, author, content_list, base_name="ebook", cover_image=None):
"""
Helper to create both formats.
content_list: List of dicts with 'title' and 'content'.
"""
builder = BookBuilder(title, author, cover_image=cover_image)
for item in content_list:
builder.add_chapter(item["title"], item["content"])
os.makedirs("exports", exist_ok=True)
epub_file = builder.generate_epub(f"exports/{base_name}.epub")
pdf_file = builder.generate_pdf(f"exports/{base_name}.pdf")
return epub_file, pdf_file