#!/usr/bin/env bash # Print Menu System # Interactive printer selection and options configuration set -euo pipefail TEMP_DIR="/tmp/rofi-print-$$" mkdir -p "$TEMP_DIR" trap 'rm -rf "$TEMP_DIR"' EXIT # Function to get list of printers get_printers() { lpstat -p 2>/dev/null | awk '{print $2}' | sort } # Function to get printer options using lpoptions get_printer_options() { local printer="$1" lpoptions -p "$printer" -l 2>/dev/null || echo "" } # Function to parse option values parse_option_line() { local line="$1" local option_name=$(echo "$line" | cut -d'/' -f1 | tr -d ' ') local values=$(echo "$line" | sed 's/^[^:]*: //') echo "$option_name|$values" } # Function to get current default value get_default_value() { local values="$1" echo "$values" | grep -o '\*[^ ]*' | tr -d '*' || echo "" } # Function to get all available values get_available_values() { local values="$1" echo "$values" | tr ' ' '\n' | tr -d '*' } # Main script main() { FILE="$1" if [ ! -f "$FILE" ]; then echo "File not provided or not found: $FILE" >&2 exit 1 fi # Get available printers PRINTERS=$(get_printers) if [ -z "$PRINTERS" ]; then echo "No printers found" >&2 exit 1 fi # Select printer PRINTER=$(echo "$PRINTERS" | fuzzel --dmenu -i -p "Select printer") if [ -z "$PRINTER" ]; then echo "No printer selected" >&2 exit 1 fi # Get printer options OPTIONS=$(get_printer_options "$PRINTER") # Build lp command LP_OPTS=() # Process each option declare -A selected_options while IFS= read -r line; do if [ -z "$line" ]; then continue; fi # Parse option line IFS='|' read -r opt_name values <<< "$(parse_option_line "$line")" if [ -z "$opt_name" ] || [ -z "$values" ]; then continue; fi # Get default and available values default=$(get_default_value "$values") available=$(get_available_values "$values") # Create friendly names for common options case "$opt_name" in *Duplex*|*Sided*) friendly_name="Duplex (Double-sided)" ;; *Staple*) friendly_name="Stapling" ;; *MediaType*) friendly_name="Paper Type" ;; *PageSize*|*media*) friendly_name="Paper Size" ;; *OutputBin*) friendly_name="Output Tray" ;; *Collate*) friendly_name="Collate" ;; *ColorModel*|*Color*) friendly_name="Color Mode" ;; *Resolution*) friendly_name="Print Quality" ;; *) friendly_name="$opt_name" ;; esac # Present options to user with default highlighted available_with_default=$(echo "$available" | sed "s/^${default}$/${default} (default)/") selected=$(echo "$available_with_default" | fuzzel --dmenu -i -p "$friendly_name") if [ -n "$selected" ]; then # Remove " (default)" suffix if present selected=$(echo "$selected" | sed 's/ (default)$//') # Only add if different from default if [ "$selected" != "$default" ]; then selected_options["$opt_name"]="$selected" fi fi done <<< "$OPTIONS" # Ask for number of copies COPIES=$(echo -e "1\n2\n3\n4\n5\n10\n20" | fuzzel --dmenu -i -p "Number of copies") COPIES=${COPIES:-1} # Build final lp command options for opt in "${!selected_options[@]}"; do LP_OPTS+=("-o" "${opt}=${selected_options[$opt]}") done if [ "$COPIES" -gt 1 ]; then LP_OPTS+=("-n" "$COPIES") fi # Confirmation OPTS_SUMMARY="Printer: $PRINTER\nFile: $(basename "$FILE")\nCopies: $COPIES" if [ ${#selected_options[@]} -gt 0 ]; then OPTS_SUMMARY+="\n\nOptions:" for opt in "${!selected_options[@]}"; do OPTS_SUMMARY+="\n $opt = ${selected_options[$opt]}" done fi echo lp -d "$PRINTER" "${LP_OPTS[@]}" "$FILE" 2>"$TEMP_DIR/error.log" echo "$OPTS_SUMMARY" CONFIRM=$(echo -e "Print\nCancel" | fuzzel --dmenu -i -p "Confirm print job") if [ "$CONFIRM" = "Print" ]; then # Execute print command if lp -d "$PRINTER" "${LP_OPTS[@]}" "$FILE" 2>"$TEMP_DIR/error.log"; then notify-send "Print.sh" "Print job submitted successfully" else ERROR=$(cat "$TEMP_DIR/error.log") echo "Print failed:\n$ERROR" >&2 exit 1 fi else echo "Print cancelled" exit 0 fi } main "$@"