226 lines
8.7 KiB
Bash
226 lines
8.7 KiB
Bash
#!/bin/bash
|
|
# =============================================================================
|
|
# script_print.sh - Impression photo pour photomaton
|
|
# =============================================================================
|
|
# Usage: script_print.sh "<filename>" "<media_type>" "<action_config_name>" "<copies>"
|
|
# Appele par photobooth-app via l'action Share "Impression"
|
|
#
|
|
# Imprimantes: Canon Selphy CP1300 x2 via WiFi (blanche + noire)
|
|
# Load balancing: utilise l'imprimante idle, sinon file d'attente sur la 1ere
|
|
#
|
|
# Sortie stdout parsable par printer_service.py:
|
|
# PRINTED:<printer_name>:<copies> en cas de succes
|
|
# PRINT_ERROR:<printer_name>:<raison> en cas d'erreur
|
|
# =============================================================================
|
|
#
|
|
# ── CALIBRAGE IMPRESSION ─────────────────────────────────────────────────────
|
|
#
|
|
# Selphy CP1300 — papier Postcard borderless 100x148mm
|
|
# Image traitée par photobooth-app : 2000x1333
|
|
# Overscan : 2114x1418 avec fond blanc (la Selphy rogne les bords en borderless)
|
|
# Décalage : -roll -12+8 (calibré pour l'offset naturel de l'imprimante)
|
|
# Option CUPS : PageSize=Postcard.Borderless (défaut imprimante = om_postcard-borderless_100x148mm)
|
|
# PAS de -o raw : le driver CUPS gère le rendu correctement
|
|
# =============================================================================
|
|
|
|
# (plus de TEST_MODE — paramètres calibrés définitifs ci-dessous)
|
|
|
|
set -uo pipefail
|
|
|
|
# --- Parametres ---
|
|
filename="${1:-}"
|
|
media_type="${2:-}"
|
|
action_config_name="${3:-}"
|
|
copies="${4:-1}"
|
|
# Liste CSV d'imprimantes à exclure du load-balancing (optionnel, passé par JH-Photomaton)
|
|
skip_printers="${5:-}"
|
|
|
|
# --- Noms des imprimantes CUPS (WiFi) ---
|
|
PRINTER_1="Selphy_Blanche_WiFi"
|
|
PRINTER_2="Selphy_Noire_WiFi"
|
|
|
|
# --- Logging ---
|
|
LOG_TAG="photomaton-print"
|
|
log_info() { logger -t "$LOG_TAG" "[INFO] $1"; echo "[INFO] $1"; }
|
|
log_error() { logger -t "$LOG_TAG" "[ERROR] $1"; echo "[ERROR] $1"; }
|
|
|
|
# --- Validation ---
|
|
if [ -z "$filename" ]; then
|
|
log_error "Aucun fichier specifie"
|
|
exit 1
|
|
fi
|
|
|
|
if [ ! -f "$filename" ]; then
|
|
log_error "Fichier introuvable: $filename"
|
|
exit 1
|
|
fi
|
|
|
|
if [ "$copies" -lt 1 ] || [ "$copies" -gt 3 ]; then
|
|
log_error "Nombre de copies invalide: $copies (doit etre entre 1 et 3)"
|
|
exit 1
|
|
fi
|
|
|
|
# --- Preparation de l'image pour impression ---
|
|
filename_no_ext="${filename%.jpg}"
|
|
filename_print="${filename_no_ext}_print.jpg"
|
|
|
|
if ! command -v convert &>/dev/null; then
|
|
log_error "ImageMagick (convert) non installe — impression de l'original"
|
|
FILE_TO_PRINT="$filename"
|
|
PRINT_OPTIONS="-o PageSize=Postcard.Borderless"
|
|
else
|
|
log_info "Preparation image pour impression borderless..."
|
|
if convert "$filename" \
|
|
-resize 2000x1333 \
|
|
-background white \
|
|
-gravity center \
|
|
-extent 2114x1418 \
|
|
-roll -12+8 \
|
|
-quality 95 \
|
|
"$filename_print" 2>/dev/null; then
|
|
FILE_TO_PRINT="$filename_print"
|
|
PRINT_OPTIONS="-o PageSize=Postcard.Borderless"
|
|
log_info "Image preparee: 2114x1418 (overscan+roll) → $filename_print"
|
|
else
|
|
log_error "Echec convert — impression de l'original"
|
|
FILE_TO_PRINT="$filename"
|
|
PRINT_OPTIONS="-o PageSize=Postcard.Borderless"
|
|
fi
|
|
fi
|
|
|
|
# --- Selection de l'imprimante (load balancing) ---
|
|
printer_1_status=$(lpstat -p "$PRINTER_1" 2>/dev/null || echo "not found")
|
|
printer_2_status=$(lpstat -p "$PRINTER_2" 2>/dev/null || echo "not found")
|
|
|
|
# Verifie si une imprimante est dans la liste skip_printers (CSV)
|
|
is_skipped() { [[ ",$skip_printers," == *",$1,"* ]]; }
|
|
|
|
# Une imprimante est utilisable si CUPS la connait ET qu'elle n'est pas exclue
|
|
p1_ok=false
|
|
p2_ok=false
|
|
[[ "$printer_1_status" != "not found" ]] && ! is_skipped "$PRINTER_1" && p1_ok=true
|
|
[[ "$printer_2_status" != "not found" ]] && ! is_skipped "$PRINTER_2" && p2_ok=true
|
|
|
|
SELECTED_PRINTER=""
|
|
|
|
if $p1_ok && [[ "$printer_1_status" == *"idle"* ]]; then
|
|
SELECTED_PRINTER="$PRINTER_1"
|
|
log_info "Imprimante selectionnee: $PRINTER_1 (idle)"
|
|
elif $p2_ok && [[ "$printer_2_status" == *"idle"* ]]; then
|
|
SELECTED_PRINTER="$PRINTER_2"
|
|
log_info "Imprimante selectionnee: $PRINTER_2 (idle)"
|
|
elif $p1_ok && $p2_ok; then
|
|
# Les deux sont accessibles mais aucune n'est idle — load balance sur les jobs
|
|
jobs_1=$(lpstat -o "$PRINTER_1" 2>/dev/null | wc -l)
|
|
jobs_2=$(lpstat -o "$PRINTER_2" 2>/dev/null | wc -l)
|
|
if [ "$jobs_1" -le "$jobs_2" ] 2>/dev/null; then
|
|
SELECTED_PRINTER="$PRINTER_1"
|
|
else
|
|
SELECTED_PRINTER="$PRINTER_2"
|
|
fi
|
|
log_info "Load balancing: $SELECTED_PRINTER (P1=$jobs_1 jobs, P2=$jobs_2 jobs)"
|
|
elif $p1_ok; then
|
|
SELECTED_PRINTER="$PRINTER_1"
|
|
log_info "Seule imprimante disponible: $PRINTER_1 (P2 inaccessible ou exclue)"
|
|
elif $p2_ok; then
|
|
SELECTED_PRINTER="$PRINTER_2"
|
|
log_info "Seule imprimante disponible: $PRINTER_2 (P1 inaccessible ou exclue)"
|
|
else
|
|
log_error "Aucune imprimante accessible dans CUPS"
|
|
echo "PRINT_ERROR::no_printer_available"
|
|
[ -f "$filename_print" ] && rm -f "$filename_print" 2>/dev/null
|
|
exit 1
|
|
fi
|
|
|
|
# --- Impression ---
|
|
log_info "Impression x${copies} sur $SELECTED_PRINTER: $FILE_TO_PRINT"
|
|
|
|
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}"
|
|
|
|
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
|
|
|
|
# --- Sondage IPP direct (Selphy CP1300 port 631, sans auth) ---
|
|
PRINTER_IP=$(lpstat -v "$SELECTED_PRINTER" 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' | head -1)
|
|
IPP_URI=""
|
|
IPP_TEST="/usr/share/cups/ipptool/get-printer-attributes.test"
|
|
if [ -n "$PRINTER_IP" ] && command -v ipptool &>/dev/null && [ -f "$IPP_TEST" ]; then
|
|
IPP_URI="ipp://${PRINTER_IP}:631/ipp/print"
|
|
log_info "Sondage IPP direct actif: $IPP_URI"
|
|
else
|
|
log_info "Sondage IPP desactive (IP=${PRINTER_IP:-inconnu})"
|
|
fi
|
|
|
|
IPP_ERROR_REASONS="input-tray-missing|media-empty|media-needed|marker-supply-empty|cover-open|door-open|offline-report"
|
|
|
|
# --- Suivi du job CUPS ---
|
|
MAX_WAIT=90
|
|
POLL_INTERVAL=3
|
|
elapsed=0
|
|
|
|
log_info "Suivi du job (max ${MAX_WAIT}s)..."
|
|
|
|
while [ $elapsed -lt $MAX_WAIT ]; do
|
|
sleep $POLL_INTERVAL
|
|
elapsed=$((elapsed + POLL_INTERVAL))
|
|
|
|
# 1. Succes CUPS
|
|
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
|
|
|
|
# 2. Erreur IPP directe (papier absent, capot ouvert, etc.)
|
|
if [ -n "$IPP_URI" ]; then
|
|
ipp_reasons=$(ipptool -tv "$IPP_URI" "$IPP_TEST" 2>/dev/null \
|
|
| grep "printer-state-reasons" | head -1)
|
|
if echo "$ipp_reasons" | grep -qiE "$IPP_ERROR_REASONS"; then
|
|
reason=$(echo "$ipp_reasons" | grep -oiE "$IPP_ERROR_REASONS" | head -1)
|
|
log_error "Erreur imprimante via IPP: $reason (${elapsed}s)"
|
|
cancel "$JOB_ID" 2>/dev/null || true
|
|
echo "PRINT_ERROR:${SELECTED_PRINTER}:${reason}"
|
|
[ -f "$filename_print" ] && rm -f "$filename_print" 2>/dev/null
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
# 3. Fallback CUPS stopped/disabled
|
|
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 stoppee CUPS: ${reason:-stopped} (${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
|
|
|
|
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
|