diff --git a/Opencode/scripts/script_print.sh b/Opencode/scripts/script_print.sh index b2aab44..f284a41 100644 --- a/Opencode/scripts/script_print.sh +++ b/Opencode/scripts/script_print.sh @@ -113,26 +113,67 @@ fi # --- Impression --- log_info "Impression x${copies} sur $SELECTED_PRINTER: $FILE_TO_PRINT" -if lp -n "$copies" -d "$SELECTED_PRINTER" $PRINT_OPTIONS "$FILE_TO_PRINT"; then - log_info "Job d'impression envoye avec succes" - - # Sortie parsable par Node-RED pour les compteurs - echo "PRINTED:${SELECTED_PRINTER}:${copies}" - - # Nettoyage du fichier temporaire (apres que CUPS l'ait lu) - if [ "$FILE_TO_PRINT" = "$filename_print" ] && [ -f "$filename_print" ]; then - (sleep 30 && rm -f "$filename_print" 2>/dev/null) & - fi - - exit 0 -else - log_error "Echec de l'envoi du job d'impression" - echo "PRINT_ERROR:${SELECTED_PRINTER}" - - # Nettoyage meme en cas d'erreur - if [ -f "$filename_print" ]; then - rm -f "$filename_print" 2>/dev/null - fi +# Envoi du job CUPS et capture du job ID +job_output=$(lp -n "$copies" -d "$SELECTED_PRINTER" $PRINT_OPTIONS "$FILE_TO_PRINT" 2>&1) +lp_exit=$? +if [ $lp_exit -ne 0 ]; then + log_error "lp a echoue (exit $lp_exit): $job_output" + echo "PRINT_ERROR:${SELECTED_PRINTER}:lp_failed" + [ -f "$filename_print" ] && rm -f "$filename_print" 2>/dev/null exit 1 fi + +# Extraction du job ID (ex: "request id is Selphy_Blanche_WiFi-42 (1 file(s))") +JOB_ID=$(echo "$job_output" | grep -oE '[A-Za-z0-9_-]+-[0-9]+' | head -1) +log_info "Job CUPS accepte: ${JOB_ID:-inconnu}" + +# Si le job ID est introuvable, comportement legacy (retour immediat) +if [ -z "$JOB_ID" ]; then + log_info "Job ID non extrait – impression reputee reussie" + echo "PRINTED:${SELECTED_PRINTER}:${copies}" + [ "$FILE_TO_PRINT" = "$filename_print" ] && (sleep 30 && rm -f "$filename_print" 2>/dev/null) & + exit 0 +fi + +# --- Suivi du job CUPS (attend la completion physique) --- +MAX_WAIT=90 # secondes max (Selphy CP1300 ~ 60s) +POLL_INTERVAL=3 +elapsed=0 + +log_info "Suivi du job CUPS (max ${MAX_WAIT}s)..." + +while [ $elapsed -lt $MAX_WAIT ]; do + sleep $POLL_INTERVAL + elapsed=$((elapsed + POLL_INTERVAL)) + + # Succes : job dans la liste des jobs termines + if lpstat -W completed 2>/dev/null | grep -q "^${JOB_ID} "; then + log_info "Job $JOB_ID termine avec succes (${elapsed}s)" + echo "PRINTED:${SELECTED_PRINTER}:${copies}" + [ "$FILE_TO_PRINT" = "$filename_print" ] && rm -f "$filename_print" 2>/dev/null + exit 0 + fi + + # Erreur : imprimante stoppee (papier absent, capot ouvert, etc.) + printer_state=$(lpstat -p "$SELECTED_PRINTER" 2>/dev/null || true) + if echo "$printer_state" | grep -qiE "stopped|disabled"; then + reason=$(lpstat -l -p "$SELECTED_PRINTER" 2>/dev/null \ + | grep -i "Reason:" | head -1 \ + | sed 's/.*Reason:[[:space:]]*//' | xargs) + log_error "Imprimante $SELECTED_PRINTER en erreur: ${reason:-stopped} (apres ${elapsed}s)" + cancel "$JOB_ID" 2>/dev/null || true + echo "PRINT_ERROR:${SELECTED_PRINTER}:${reason:-stopped}" + [ -f "$filename_print" ] && rm -f "$filename_print" 2>/dev/null + exit 1 + fi + + log_info "Impression en cours... (${elapsed}s / ${MAX_WAIT}s)" +done + +# Timeout : annule le job CUPS +log_error "Timeout impression apres ${MAX_WAIT}s (job: $JOB_ID)" +cancel "$JOB_ID" 2>/dev/null || true +echo "PRINT_ERROR:${SELECTED_PRINTER}:timeout_${MAX_WAIT}s" +[ -f "$filename_print" ] && rm -f "$filename_print" 2>/dev/null +exit 1 diff --git a/backend/services/printer_service.py b/backend/services/printer_service.py index 599f25a..444fe86 100644 --- a/backend/services/printer_service.py +++ b/backend/services/printer_service.py @@ -235,17 +235,26 @@ class PrinterService: cmd = ["/bin/bash", script, filename, "image", "default", str(copies)] try: proc = subprocess.run( - cmd, capture_output=True, text=True, timeout=60 + cmd, capture_output=True, text=True, timeout=120 ) stdout = proc.stdout.strip() - if proc.returncode == 0 and "PRINTED:" in stdout: - parts = stdout.split(":") - printer = parts[1] if len(parts) > 1 else "" - return {"success": True, "printer": printer, "output": stdout} - else: - return {"success": False, "error": proc.stderr.strip() or stdout, "printer": ""} + # Cherche PRINTED: ou PRINT_ERROR: dans la dernière ligne significative + for line in reversed(stdout.splitlines()): + line = line.strip() + if line.startswith("PRINTED:"): + parts = line.split(":") + printer = parts[1] if len(parts) > 1 else "" + return {"success": True, "printer": printer, "output": stdout} + if line.startswith("PRINT_ERROR:"): + parts = line.split(":", 2) + printer = parts[1] if len(parts) > 1 else "" + reason = parts[2] if len(parts) > 2 else "" + err_msg = f"Erreur imprimante {printer}: {reason}" if reason else f"Erreur imprimante {printer}" + return {"success": False, "error": err_msg, "printer": printer} + # Aucun marqueur reconnu + return {"success": False, "error": proc.stderr.strip() or stdout or "Script sans sortie reconnue", "printer": ""} except subprocess.TimeoutExpired: - return {"success": False, "error": "Timeout impression (60s)"} + return {"success": False, "error": "Timeout impression (120s)"} except Exception as e: return {"success": False, "error": str(e)} diff --git a/frontend/templates/admin/actions.html b/frontend/templates/admin/actions.html index 0af8258..1e6970e 100644 --- a/frontend/templates/admin/actions.html +++ b/frontend/templates/admin/actions.html @@ -1,15 +1,6 @@ {% extends "base.html" %} {% block title %}Actions — JH Photomaton{% endblock %} -{% block nav_links %} -Dashboard -Galerie -Actions -Impression -Réglages -Événements -Déconnexion -{% endblock %} {% block content %}
diff --git a/frontend/templates/admin/events.html b/frontend/templates/admin/events.html index 9d6efaa..57fd3b1 100644 --- a/frontend/templates/admin/events.html +++ b/frontend/templates/admin/events.html @@ -1,15 +1,6 @@ {% extends "base.html" %} {% block title %}Événements — JH Photomaton{% endblock %} -{% block nav_links %} -Dashboard -Galerie -Actions -Impression -Réglages -Événements -Déconnexion -{% endblock %} {% block head %}