diff --git a/home/print/app.py b/home/print/app.py new file mode 100644 index 0000000..9130f12 --- /dev/null +++ b/home/print/app.py @@ -0,0 +1,138 @@ +import os +import subprocess +from pathlib import Path + +import pypdf +from flask import Flask, flash, redirect, render_template, request, url_for +from werkzeug.utils import secure_filename + +UPLOAD_FOLDER = str(Path(__file__).parent / "uploads") +ALLOWED_EXTENSIONS = {"pdf"} +PRINTER_NAME = "HL-2270DW_series" +MAX_PAGES = 10 +MAX_COPIES = 10 + +app = Flask(__name__) +app.config["UPLOAD_FOLDER"] = UPLOAD_FOLDER +app.config["SECRET_KEY"] = os.urandom(24) +app.config["MAX_CONTENT_LENGTH"] = 16 * 1024 * 1024 + + +def allowed_file(filename): + return "." in filename and filename.rsplit(".", 1)[1].lower() in ALLOWED_EXTENSIONS + + +def get_printer_warning(): + try: + result = subprocess.run( + ["lpstat", "-l", "-p", PRINTER_NAME], + capture_output=True, text=True, timeout=3 + ) + output = result.stdout.lower() + first_line = result.stdout.splitlines()[0] if result.stdout else "" + if "stopped" in first_line.lower() or "offline" in first_line.lower(): + paper_keywords = ("media empty", "out of paper", "paper", "tray empty", "no media") + if any(kw in output for kw in paper_keywords): + return "Printer appears to be out of paper." + return "Printer is stopped or offline and may not accept jobs." + except Exception: + pass + return None + + +def get_pdf_page_count(filepath): + try: + with open(filepath, "rb") as f: + reader = pypdf.PdfReader(f) + return len(reader.pages) + except Exception as e: + app.logger.error(f"Could not read PDF pages: {e}") + return None + + +@app.route("/", methods=["GET", "POST"]) +def upload_and_print(): + if request.method == "POST": + if "file" not in request.files: + flash("No file part in the request.", "error") + return redirect(request.url) + + file = request.files["file"] + + if file.filename == "": + flash("No file selected. Please choose a PDF to print.", "error") + return redirect(request.url) + + if file and allowed_file(file.filename): + try: + copies = int(request.form.get("copies", 1)) + except ValueError: + copies = 1 + copies = max(1, min(copies, MAX_COPIES)) + + filename = secure_filename(file.filename) + os.makedirs(app.config["UPLOAD_FOLDER"], exist_ok=True) + filepath = os.path.join(app.config["UPLOAD_FOLDER"], filename) + file.save(filepath) + + try: + page_count = get_pdf_page_count(filepath) + if page_count is None: + flash( + "Could not process the PDF file. It might be corrupt.", "error" + ) + return redirect(request.url) + + if page_count > MAX_PAGES: + flash( + f"Error: File has {page_count} pages. The maximum allowed is {MAX_PAGES}.", + "error", + ) + return redirect(request.url) + + app.logger.info( + f"Sending '{filename}' ({page_count} pages, {copies} copies) to printer '{PRINTER_NAME}'" + ) + command = [ + "lp", + "-d", + PRINTER_NAME, + "-n", + str(copies), + filepath, + ] + result = subprocess.run( + command, capture_output=True, text=True, check=True + ) + app.logger.info(f"lp command stdout: {result.stdout}") + copy_word = "copy" if copies == 1 else "copies" + flash(f"Success! '{filename}' ({copies} {copy_word}) has been sent to the printer.", "success") + + except subprocess.CalledProcessError as e: + app.logger.error(f"Error printing file: {e}") + app.logger.error(f"lp command stderr: {e.stderr}") + flash( + "Error sending file to printer. The printer may be offline or misconfigured.", + "error", + ) + + except Exception as e: + app.logger.error(f"An unexpected error occurred: {e}") + flash("An unexpected server error occurred.", "error") + + finally: + if os.path.exists(filepath): + os.remove(filepath) + app.logger.info(f"Cleaned up temporary file: {filepath}") + + return redirect(url_for("upload_and_print")) + + else: + flash("Invalid file type. Please upload a PDF file.", "error") + return redirect(request.url) + + return render_template("index.html", printer_name=PRINTER_NAME, max_pages=MAX_PAGES, max_copies=MAX_COPIES, printer_warning=get_printer_warning()) + + +if __name__ == "__main__": + app.run(host="127.0.0.1", port=57928, debug=False) diff --git a/home/print/templates/index.html b/home/print/templates/index.html index 03ea98d..5f079a0 100644 --- a/home/print/templates/index.html +++ b/home/print/templates/index.html @@ -26,6 +26,12 @@
(Max {{ max_pages }} pages)
+ {% if printer_warning %} +