Initial commit
This commit is contained in:
11
home-server/printing/server/Dockerfile
Normal file
11
home-server/printing/server/Dockerfile
Normal file
@@ -0,0 +1,11 @@
|
||||
FROM python:3
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y libcups2-dev python3-pip cups python3-cups gcc \
|
||||
&& pip install pycups fastapi "uvicorn[standard]" python-multipart
|
||||
|
||||
|
||||
WORKDIR /app
|
||||
COPY ./src .
|
||||
|
||||
CMD python -m uvicorn print_api:app --reload --host 0.0.0.0 --port 6311
|
||||
27
home-server/printing/server/flake.lock
generated
Normal file
27
home-server/printing/server/flake.lock
generated
Normal file
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"nodes": {
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1725634671,
|
||||
"narHash": "sha256-v3rIhsJBOMLR8e/RNWxr828tB+WywYIoajrZKFM+0Gg=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "574d1eac1c200690e27b8eb4e24887f8df7ac27c",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nixos",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
||||
38
home-server/printing/server/flake.nix
Normal file
38
home-server/printing/server/flake.nix
Normal file
@@ -0,0 +1,38 @@
|
||||
{
|
||||
description = "Printer Server Flake";
|
||||
inputs = {
|
||||
nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
|
||||
};
|
||||
outputs = { self, nixpkgs, ... }:
|
||||
let
|
||||
system = "x86_64-linux";
|
||||
pkgs = import nixpkgs { inherit system; };
|
||||
myPython = pkgs.python3.withPackages (python-pkgs: with pkgs; [
|
||||
python312Packages.fastapi
|
||||
python312Packages.fastapi-cli
|
||||
python312Packages.pycups
|
||||
python312Packages.python-multipart
|
||||
python312Packages.uvicorn
|
||||
]);
|
||||
in
|
||||
{
|
||||
devShells.${system}.default = pkgs.mkShell {
|
||||
packages = with pkgs; [
|
||||
python312Packages.fastapi
|
||||
python312Packages.fastapi-cli
|
||||
python312Packages.pycups
|
||||
python312Packages.python-multipart
|
||||
python312Packages.uvicorn
|
||||
];
|
||||
};
|
||||
|
||||
packages.${system} = rec {
|
||||
fastapi-server = pkgs.writeShellScriptBin "start-server" ''
|
||||
${myPython}/bin/fastapi run ${self}/src/print_api.py
|
||||
'';
|
||||
|
||||
default = fastapi-server;
|
||||
};
|
||||
|
||||
};
|
||||
}
|
||||
149
home-server/printing/server/src/index.html
Normal file
149
home-server/printing/server/src/index.html
Normal file
@@ -0,0 +1,149 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Document Upload</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 100vh;
|
||||
background: #09373e;
|
||||
color: #85bfc8;
|
||||
}
|
||||
#form-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
form {
|
||||
border: 1px solid #ccc;
|
||||
padding: 20px;
|
||||
background: #05252a;
|
||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
h2 {
|
||||
margin-bottom: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
input[type="file"] {
|
||||
display: none; /* Hide the file input */
|
||||
}
|
||||
input[type="submit"] {
|
||||
padding: 10px 20px;
|
||||
border: none;
|
||||
background: #007bff;
|
||||
color: #fff;
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
}
|
||||
input[type="submit"]:hover {
|
||||
background: #0056b3;
|
||||
}
|
||||
|
||||
#dropzone {
|
||||
border: 2px dashed #ccc;
|
||||
padding: 20px;
|
||||
width: 300px;
|
||||
text-align: center;
|
||||
color: #ccc;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#dropzone.dragover {
|
||||
border-color: #000;
|
||||
color: #000;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h2>Upload Document</h2>
|
||||
<br />
|
||||
<section id="form-container">
|
||||
<form
|
||||
id="printForm"
|
||||
action="/print/"
|
||||
method="post"
|
||||
enctype="multipart/form-data"
|
||||
>
|
||||
<div id="dropzone">Drop file to upload or click to select</div>
|
||||
<input type="file" id="fileInput" />
|
||||
<br />
|
||||
<input type="submit" value="Upload Document" name="submit" />
|
||||
</form>
|
||||
</section>
|
||||
<script>
|
||||
var stagedFile = undefined;
|
||||
const formElement = document.getElementById("printForm");
|
||||
const fileInputElement = document.getElementById("fileInput");
|
||||
|
||||
formElement.addEventListener("submit", async (e) => {
|
||||
e.preventDefault();
|
||||
const formData = new FormData();
|
||||
formData.append("file", stagedFile);
|
||||
|
||||
const response = await fetch("/print/", {
|
||||
method: "POST",
|
||||
body: formData,
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
console.log(data);
|
||||
});
|
||||
|
||||
document
|
||||
.getElementById("dropzone")
|
||||
.addEventListener("dragover", function (event) {
|
||||
event.preventDefault(); // Prevent default behavior (Prevent file from being opened)
|
||||
event.stopPropagation();
|
||||
event.target.classList.add("dragover"); // Optional: add a style change
|
||||
});
|
||||
|
||||
document
|
||||
.getElementById("dropzone")
|
||||
.addEventListener("dragleave", function (event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
event.target.classList.remove("dragover"); // Optional: revert style change
|
||||
});
|
||||
|
||||
document
|
||||
.getElementById("dropzone")
|
||||
.addEventListener("drop", function (event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
event.target.classList.remove("dragover"); // Optional: revert style change
|
||||
|
||||
// Process files
|
||||
var files = event.dataTransfer.files;
|
||||
handleFiles(files);
|
||||
});
|
||||
|
||||
// Handle file selection when clicked
|
||||
document
|
||||
.getElementById("dropzone")
|
||||
.addEventListener("click", function () {
|
||||
fileInputElement.click(); // Trigger the hidden file input's click
|
||||
});
|
||||
|
||||
fileInputElement.addEventListener("change", function (event) {
|
||||
const files = event.target.files;
|
||||
handleFiles(files);
|
||||
});
|
||||
|
||||
const handleFiles = (files) => {
|
||||
stagedFile = files[0];
|
||||
renderStagedFile();
|
||||
};
|
||||
|
||||
const renderStagedFile = () => {
|
||||
const element = document.getElementById("dropzone");
|
||||
if (!stagedFile) {
|
||||
element.textContent = "Drop file to upload or click to select";
|
||||
} else {
|
||||
element.textContent = `FILE: ${stagedFile.name}`;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
69
home-server/printing/server/src/print_api.py
Normal file
69
home-server/printing/server/src/print_api.py
Normal file
@@ -0,0 +1,69 @@
|
||||
import os
|
||||
from pprint import pprint
|
||||
import tempfile
|
||||
from fastapi import FastAPI, File, UploadFile, Request
|
||||
import cups
|
||||
from fastapi.responses import HTMLResponse
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
# @app.post("/print/")
|
||||
# async def print_document(file: UploadFile = File(...)):
|
||||
# temp_file = tempfile.NamedTemporaryFile(delete=False)
|
||||
# temp_file.write(await file.read())
|
||||
# temp_file.close()
|
||||
|
||||
# conn = cups.Connection(host="server.alexmickelson.guru")
|
||||
|
||||
# printers = conn.getPrinters()
|
||||
# print(file.filename)
|
||||
# print(temp_file.name)
|
||||
# pprint(printers)
|
||||
# for printer in printers:
|
||||
# print(printer, printers[printer]["device-uri"])
|
||||
|
||||
# default_printer = list(printers.keys())[0]
|
||||
|
||||
|
||||
# job_id = conn.printFile(default_printer, temp_file.name, f"FastAPI Print Job for {temp_file.name}", {})
|
||||
# os.unlink(temp_file.name)
|
||||
|
||||
# return {"job_id": job_id, "file_name": file.filename}
|
||||
|
||||
|
||||
@app.post("/print/")
|
||||
async def print_document(file: UploadFile = File(...)):
|
||||
# Save the uploaded file to a temporary file
|
||||
temp_file = tempfile.NamedTemporaryFile(delete=False)
|
||||
temp_file.write(await file.read())
|
||||
temp_file.close()
|
||||
|
||||
# Connect to the CUPS server on the host (use default CUPS connection)
|
||||
conn = cups.Connection() # This will connect to localhost CUPS
|
||||
|
||||
# Get the list of available printers
|
||||
printers = conn.getPrinters()
|
||||
print(file.filename)
|
||||
print(temp_file.name)
|
||||
pprint(printers)
|
||||
for printer in printers:
|
||||
print(printer, printers[printer]["device-uri"])
|
||||
|
||||
# Use the default printer (first one in the list)
|
||||
default_printer = list(printers.keys())[0]
|
||||
|
||||
# Print the file
|
||||
job_id = conn.printFile(default_printer, temp_file.name, f"FastAPI Print Job for {temp_file.name}", {})
|
||||
|
||||
# Clean up the temporary file
|
||||
os.unlink(temp_file.name)
|
||||
|
||||
return {"job_id": job_id, "file_name": file.filename}
|
||||
|
||||
@app.get("/", response_class=HTMLResponse)
|
||||
async def read_root(request: Request):
|
||||
with open('src/index.html', 'r') as f:
|
||||
html_content = f.read()
|
||||
return HTMLResponse(content=html_content, status_code=200)
|
||||
|
||||
Reference in New Issue
Block a user