148 lines
4.5 KiB
Python
148 lines
4.5 KiB
Python
import os
|
|
import logging
|
|
import pypandoc
|
|
from config import SUPPORTED_FORMATS
|
|
from bookish.services.sse_manager import update_progress, mark_complete, mark_error
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
def get_format_from_ext(filename):
|
|
ext = os.path.splitext(filename)[1].lower().lstrip(".")
|
|
if ext in SUPPORTED_FORMATS:
|
|
return ext
|
|
# mappa alias comuni
|
|
alias = {"markdown": "md", "text": "txt", "latex": "latex", "tex": "latex"}
|
|
return alias.get(ext, ext)
|
|
|
|
|
|
def run_conversion(input_path, output_path, input_format, output_format, task_id, filename):
|
|
"""
|
|
Esegue la conversione con Pandoc, aggiornando il progresso via SSE.
|
|
Per alcuni formati speciali delega a formatter.py.
|
|
"""
|
|
try:
|
|
update_progress(task_id, 10, "analyzing")
|
|
_validate_pandoc_format(input_format, output_format)
|
|
|
|
update_progress(task_id, 30, "converting")
|
|
|
|
if input_format == "docx" and output_format == "pdf":
|
|
_convert_docx_to_pdf(input_path, output_path, task_id)
|
|
elif output_format == "pdf":
|
|
_convert_to_pdf(input_path, output_path, input_format, task_id)
|
|
else:
|
|
_convert_with_pandoc(input_path, output_path, input_format, output_format, task_id)
|
|
|
|
update_progress(task_id, 90, "finalizing")
|
|
update_progress(task_id, 100)
|
|
mark_complete(task_id, os.path.basename(output_path))
|
|
|
|
except Exception as e:
|
|
logger.exception("Conversione fallita: %s -> %s (%s)", input_format, output_format, filename)
|
|
mark_error(task_id, str(e))
|
|
|
|
|
|
def _validate_pandoc_format(input_format, output_format):
|
|
"""Verifica che Pandoc supporti input/output format."""
|
|
try:
|
|
readers = pypandoc.get_pandoc_formats()[0]
|
|
writers = pypandoc.get_pandoc_formats()[1]
|
|
except Exception as e:
|
|
raise RuntimeError(f"Errore Pandoc: {e}. Installalo con: pip install pypandoc-binary")
|
|
|
|
pandoc_input = _to_pandoc_format(input_format)
|
|
pandoc_output = _to_pandoc_format(output_format)
|
|
|
|
if pandoc_input not in readers:
|
|
raise ValueError(f"Formato input '{input_format}' non supportato da Pandoc")
|
|
if pandoc_output not in writers:
|
|
raise ValueError(f"Formato output '{output_format}' non supportato da Pandoc")
|
|
|
|
|
|
def _to_pandoc_format(fmt):
|
|
mapping = {
|
|
"md": "markdown",
|
|
"latex": "latex",
|
|
"tex": "latex",
|
|
"html": "html",
|
|
"epub": "epub",
|
|
"pdf": "pdf",
|
|
"docx": "docx",
|
|
"txt": "plain",
|
|
"fb2": "fb2",
|
|
"mobi": "mobi",
|
|
}
|
|
return mapping.get(fmt, fmt)
|
|
|
|
|
|
def _convert_with_pandoc(input_path, output_path, input_format, output_format, task_id):
|
|
extra_args = ["--wrap=preserve"]
|
|
if output_format == "epub":
|
|
extra_args += ["--metadata", "title=Converted Document"]
|
|
if output_format == "html":
|
|
extra_args += ["--self-contained", "--mathjax"]
|
|
|
|
pandoc_input = _to_pandoc_format(input_format)
|
|
pandoc_output = _to_pandoc_format(output_format)
|
|
|
|
def callback(percent):
|
|
scaled = 30 + int(percent * 0.5)
|
|
update_progress(task_id, min(scaled, 85))
|
|
|
|
pypandoc.convert_file(
|
|
input_path,
|
|
pandoc_output,
|
|
format=pandoc_input,
|
|
outputfile=output_path,
|
|
extra_args=extra_args,
|
|
)
|
|
|
|
|
|
def _convert_to_pdf(input_path, output_path, input_format, task_id):
|
|
"""Converte in PDF usando Pandoc con WeasyPrint."""
|
|
from bookish.services.formatter import html_to_pdf
|
|
|
|
update_progress(task_id, 40, "converting")
|
|
html_path = output_path.replace(".pdf", ".html")
|
|
|
|
pandoc_input = _to_pandoc_format(input_format)
|
|
pypandoc.convert_file(
|
|
input_path,
|
|
"html",
|
|
format=pandoc_input,
|
|
outputfile=html_path,
|
|
extra_args=["--wrap=preserve", "--self-contained"],
|
|
)
|
|
|
|
update_progress(task_id, 65, "converting")
|
|
html_to_pdf(html_path, output_path)
|
|
|
|
if os.path.exists(html_path):
|
|
os.remove(html_path)
|
|
|
|
|
|
def _convert_docx_to_pdf(input_path, output_path, task_id):
|
|
"""DOCX → PDF via Pandoc → HTML → WeasyPrint."""
|
|
from bookish.services.formatter import html_to_pdf
|
|
|
|
update_progress(task_id, 40, "converting")
|
|
html_path = output_path.replace(".pdf", ".html")
|
|
|
|
pypandoc.convert_file(
|
|
input_path,
|
|
"html",
|
|
format="docx",
|
|
outputfile=html_path,
|
|
extra_args=["--wrap=preserve"],
|
|
)
|
|
|
|
update_progress(task_id, 65, "converting")
|
|
html_to_pdf(html_path, output_path)
|
|
|
|
if os.path.exists(html_path):
|
|
os.remove(html_path)
|
|
|
|
|
|
|