wing-ops/scripts/generate_manual_pdfs/generate.py

74 lines
2.2 KiB
Python

#!/usr/bin/env python3
"""WING-OPS 사용자 매뉴얼 챕터별 PDF 생성.
`frontend/src/common/data/chapters.json`을 읽어
`frontend/public/manual/pdfs/ch01.pdf ~ ch08.pdf`를 생성한다.
사용법:
pip install -r requirements.txt
python generate.py
"""
from __future__ import annotations
import json
from pathlib import Path
from jinja2 import Environment, FileSystemLoader, select_autoescape
from weasyprint import HTML
SCRIPT_DIR = Path(__file__).resolve().parent
REPO_ROOT = SCRIPT_DIR.parent.parent
DATA_FILE = REPO_ROOT / 'frontend' / 'src' / 'common' / 'data' / 'chapters.json'
PUBLIC_DIR = REPO_ROOT / 'frontend' / 'public'
OUT_DIR = PUBLIC_DIR / 'manual' / 'pdfs'
def load_chapters() -> list[dict]:
with DATA_FILE.open(encoding='utf-8') as fp:
return json.load(fp)
def render_pdf(chapter: dict, env: Environment) -> None:
template = env.get_template('template.html')
html_str = template.render(chapter=chapter)
# base_url: 템플릿 내부의 상대경로(manual/imageN.png, style.css)가
# frontend/public 및 scripts/generate_manual_pdfs 양쪽을 참조하므로
# public 을 base 로 두고 style.css 는 절대경로로 포함한다.
style_path = SCRIPT_DIR / 'style.css'
html_with_style = html_str.replace(
'href="style.css"',
f'href="file://{style_path}"',
)
out_path = OUT_DIR / f'{chapter["id"]}.pdf'
HTML(string=html_with_style, base_url=str(PUBLIC_DIR)).write_pdf(str(out_path))
print(f' {out_path.relative_to(REPO_ROOT)} ({out_path.stat().st_size // 1024} KB)')
def main() -> None:
if not DATA_FILE.exists():
raise SystemExit(f'chapters.json not found: {DATA_FILE}')
OUT_DIR.mkdir(parents=True, exist_ok=True)
chapters = load_chapters()
print(f'Loaded {len(chapters)} chapters from {DATA_FILE.relative_to(REPO_ROOT)}')
env = Environment(
loader=FileSystemLoader(str(SCRIPT_DIR)),
autoescape=select_autoescape(['html']),
)
for chapter in chapters:
print(f'Rendering CH {chapter["number"]} · {chapter["title"]} ({len(chapter["screens"])} screens)')
render_pdf(chapter, env)
print(f'\nDone. Output: {OUT_DIR.relative_to(REPO_ROOT)}/')
if __name__ == '__main__':
main()