import os import traceback from datetime import datetime, timezone import requests from sqlalchemy.orm import Session as SASession from server.database import Session from models.models import Conversion, ConversionStatus, EventMedia, MediaType GOTENBERG_URL = os.getenv("GOTENBERG_URL", "http://gotenberg:3000") def _now(): return datetime.now(timezone.utc) def convert_event_media_to_pdf(conversion_id: int): """ Job entry point: convert a single EventMedia to PDF using Gotenberg. Steps: - Load conversion + source media - Set status=processing, started_at - POST to Gotenberg /forms/libreoffice/convert with the source file bytes - Save response bytes to target_path - Set status=ready, completed_at, target_path - On error: set status=failed, error_message """ session: SASession = Session() try: conv: Conversion = session.query(Conversion).get(conversion_id) if not conv: return media: EventMedia = session.query( EventMedia).get(conv.source_event_media_id) if not media or not media.file_path: conv.status = ConversionStatus.failed conv.error_message = "Source media or file_path missing" conv.completed_at = _now() session.commit() return conv.status = ConversionStatus.processing conv.started_at = _now() session.commit() # Get the server directory (where this worker.py file is located) server_dir = os.path.dirname(os.path.abspath(__file__)) media_root = os.path.join(server_dir, "media") abs_source = os.path.join(media_root, media.file_path) # Output target under media/converted converted_dir = os.path.join(media_root, "converted") os.makedirs(converted_dir, exist_ok=True) filename_wo_ext = os.path.splitext( os.path.basename(media.file_path))[0] pdf_name = f"{filename_wo_ext}.pdf" abs_target = os.path.join(converted_dir, pdf_name) # Send to Gotenberg with open(abs_source, "rb") as f: files = {"files": (os.path.basename(abs_source), f)} resp = requests.post( f"{GOTENBERG_URL}/forms/libreoffice/convert", files=files, timeout=600, ) resp.raise_for_status() with open(abs_target, "wb") as out: out.write(resp.content) conv.status = ConversionStatus.ready # Store relative path under media/ conv.target_path = os.path.relpath(abs_target, media_root) conv.completed_at = _now() session.commit() except requests.exceptions.Timeout: conv = session.query(Conversion).get(conversion_id) if conv: conv.status = ConversionStatus.failed conv.error_message = "Conversion timeout" conv.completed_at = _now() session.commit() except Exception as e: conv = session.query(Conversion).get(conversion_id) if conv: conv.status = ConversionStatus.failed conv.error_message = f"{e}\n{traceback.format_exc()}" conv.completed_at = _now() session.commit() finally: session.close()