Compare commits

..

No commits in common. "c8ce4db2a2234beecadd8f6ce2f32e6f74deb697" and "8542ea2ef7d1cf989aa65b420f914f42334e1a0a" have entirely different histories.

6 changed files with 111 additions and 237 deletions

23
flake.lock generated
View file

@ -16,30 +16,9 @@
"type": "github" "type": "github"
} }
}, },
"pyproject-nix": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1758265079,
"narHash": "sha256-amLaLNwKSZPShQHzfgmc/9o76dU8xzN0743dWgvYlr8=",
"owner": "nix-community",
"repo": "pyproject.nix",
"rev": "02e9418fd4af638447dca4b17b1280da95527fc9",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "pyproject.nix",
"type": "github"
}
},
"root": { "root": {
"inputs": { "inputs": {
"nixpkgs": "nixpkgs", "nixpkgs": "nixpkgs"
"pyproject-nix": "pyproject-nix"
} }
} }
}, },

104
flake.nix
View file

@ -1,85 +1,59 @@
{ {
inputs = { inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
pyproject-nix = {
url = "github:nix-community/pyproject.nix";
inputs.nixpkgs.follows = "nixpkgs";
};
}; };
outputs = { outputs = {
self, self,
nixpkgs, nixpkgs,
...
} @ inputs: let } @ inputs: let
system = "x86_64-linux"; system = "x86_64-linux";
pkgs = import nixpkgs { pkgs = import nixpkgs {
inherit system; inherit system;
config.allowUnfree = true; config.allowUnfree = true;
}; };
python = pkgs.python3;
serverProject = inputs.pyproject-nix.lib.project.loadPyproject {
projectRoot = ./.;
};
# Packages
script = pkgs.writeShellApplication {
name = "scanbuddy";
runtimeInputs = with pkgs; [sane-backends brscan5 ghostscript];
text = builtins.readFile ./scanbuddy.bash;
};
# Returns an attribute set that can be passed to `buildPythonPackage`.
attrs = serverProject.renderers.buildPythonPackage {inherit python;};
server = python.pkgs.buildPythonPackage (attrs
// {
env.CUSTOM_ENVVAR = "foobar";
});
scanbuddy-pkg = pkgs.symlinkJoin {
name = "scanbuddy";
paths = [script server];
};
in { in {
# devShells.${system}.default = pkgs.mkShell { devShells.${system}.default = pkgs.mkShell {
# packages = with pkgs; [ packages = with pkgs; [
# python313 python313
# python313Packages.flask python313Packages.flask
# python313Packages.waitress python313Packages.waitress
# ]; ];
#
# shellHook = ''
# python --version
# exec zsh
# '';
# };
packages.${system} = {
default = scanbuddy-pkg;
inherit script;
inherit server;
};
nixosModules.default = { shellHook = ''
config, python --version
pkgs, exec zsh
lib, '';
... };
}: { packages.${system} = let
options = { scanbuddy = pkgs.writeShellApplication {
service.scanbuddy = lib.mkEnableOption "Enable the scanbuddy server"; name = "scanbuddy-script";
runtimeInputs = with pkgs; [sane-backends brscan5 ghostscript];
text = builtins.readFile ./scanbuddy.bash;
}; };
config = { wrapper = pkgs.writeShellApplication {
systemd.services.scanbuddy = lib.mkIf config.service.scanbuddy { name = "scanbuddy-wrapper";
description = "The scanbuddy webservice";
wantedBy = ["multi-user.target"]; text =
serviceConfig = { /*
ExecStart = "${scanbuddy-pkg}/bin/scanbuddy-server"; bash
Path = ["${scanbuddy-pkg}/bin"]; */
WorkingDirectory = "/var/lib/scanbuddy"; ''
}; #!/usr/bin/env bash
}; readarray -d '_' args < <(printf "%s" "$1")
scanbuddy "''${args[@]}"
'';
}; };
package = pkgs.symlinkJoin {
name = "scanbuddy";
paths = [scanbuddy wrapper];
};
in {
default = package;
inherit scanbuddy;
inherit wrapper;
}; };
}; };
} }

View file

@ -1,15 +0,0 @@
[project]
name = "scanbuddy-server"
version = "0.1.0"
description = "A REST server for the scanbuddy shell-script"
# define any Python dependencies
dependencies = [
"flask>3",
"waitress"
]
# define the CLI executable
# Here, we define the entry point to be the 'main()' function in the module 'app/main.py'
[project.scripts]
scanbuddy-server = "server.server:main"

View file

@ -13,6 +13,7 @@ sides=$simplex_source
mode='c' mode='c'
resolution='300' resolution='300'
current_page=$(find "$PWD" -name "out*.pdf" | sort | tail -n 1); current_page=$(find "$PWD" -name "out*.pdf" | sort | tail -n 1);
read -r current_pageno <<<"${current_page//[^0-9]/ }" read -r current_pageno <<<"${current_page//[^0-9]/ }"
current_pageno=${current_pageno:-0} current_pageno=${current_pageno:-0}
@ -76,33 +77,6 @@ scan() {
-x 210 -y 297 # A4 -x 210 -y 297 # A4
} }
clean() {
echo "Cleaning up..."
rm -rfv "$PWD/out*.pdf"
}
dispatch() {
readarray -d '' out_files < <(find . -regextype posix-awk -regex "\./out[0-9]+\.pdf" -print0 | sort -Vz)
combined_file=$(mktemp --suff="_scanbuddy.pdf")
gs -q -dNOPAUSE -sDEVICE=pdfwrite -sOUTPUTFILE="$combined_file" -dBATCH "${out_files[@]}"
echo "Merged pdf written to $combined_file"
# send to paperless
PAPERLESS_STATUS=$(curl \
-H "Authorization: Token $PAPERLESS_TOKEN" \
-F document=@"$combined_file" \
"$([ -v PAPERLESS_TAG ] && echo "-F tags=$PAPERLESS_TAG")" \
"${PAPERLESS_URL}/api/documents/post_document/") || FAILED=1
if [ -v FAILED ]; then
printf "Paperless failed with message:\n%s" "$PAPERLESS_STATUS"
else
printf "Paperless consumption job: %s\n" "$PAPERLESS_STATUS"
fi
clean
}
if [ "$#" -lt 1 ]; then if [ "$#" -lt 1 ]; then
echo "You need an argument!" echo "You need an argument!"
exit 1 exit 1
@ -116,12 +90,25 @@ case "$1" in
rm "$last_out_file" rm "$last_out_file"
;; ;;
dispatch) dispatch)
dispatch "${@:2}" readarray -d '' out_files < <(find . -regextype posix-awk -regex "\./out[0-9]+\.pdf" -print0 | sort -Vz)
;; combined_file=$(mktemp --suff="_scanbuddy.pdf")
clean) gs -q -dNOPAUSE -sDEVICE=pdfwrite -sOUTPUTFILE="$combined_file" -dBATCH "${out_files[@]}"
clean echo "Merged pdf written to $combined_file"
# send to paperless
PAPERLESS_STATUS=$(curl \
-H "Authorization: Token $PAPERLESS_TOKEN" \
-F document=@"$combined_file" \
"$([ -v PAPERLESS_TAG ] && echo "-F tags=$PAPERLESS_TAG")" \
"${PAPERLESS_URL}/api/documents/post_document/") || FAILED=1
if [ -v FAILED ]; then
printf "Paperless failed with message:\n%s" "$PAPERLESS_STATUS"
else
printf "Paperless consumption job: %s\n" "$PAPERLESS_STATUS"
fi
;; ;;
*) *)
echo "Usage: scanbuddy scan|unscan|dispatch|clean" echo "Usage: scanbuddy"
;; ;;
esac esac

52
server.py Executable file
View file

@ -0,0 +1,52 @@
#!/usr/bin/env python3
# Run this stuff with `waitress-serve --port=5000 --call server:create_app`
import os
import subprocess
from flask import Flask, request
app = Flask(__name__)
@app.route("/")
def hello_world():
return "Hello, World! Yoyoyo"
@app.route("/scan")
def scan():
command = ["bash", f"{os.getcwd()}/scanbuddy.bash", "scan"]
command += ["-d"] if (request.args.get("duplex", "n") == 'y') else []
result = subprocess.run(command, stdout=subprocess.PIPE, text=True)
output = result.stdout.strip()
print("Scanbuddy output: ")
print(output)
return output
# return f"Scanning {'duplex' if duplex == 'y' else ''}..."
@app.route("/dispatch")
def dispatch():
command = ["bash", f"{os.getcwd()}/scanbuddy.bash", "dispatch"]
user = request.args.get("user", "")
result = subprocess.run(command, stdout=subprocess.PIPE, text=True)
output = result.stdout.strip()
print("Scanbuddy output: ")
print(output)
return "Dispatching..."
@app.route("/unscan")
def unscan():
return "Unscanning..."
def create_app():
return app
if __name__=='__main__':
from waitress import serve
serve(app, host="0.0.0.0", port=8080)

View file

@ -1,103 +0,0 @@
#!/usr/bin/env python3
# Run this stuff with `waitress-serve --port=5000 --call server:create_app`
import os
import subprocess
from flask import Flask, request
app = Flask(__name__)
SCANBUDDY_COMMAND = ["bash", f"{os.getcwd()}/scanbuddy.bash"]
@app.route("/")
def hello_world():
return ("Scanbuddy server. Go to <ul>"
" <li><a href=\"scan\">scan</a></li>"
" <li><a href=\"unscan\">unscan</a></li>"
" <li><a href=\"dispatch\">dispatch</a></li>"
" <li><a href=\"clean\">clean</a></li>"
"</ul>")
@app.route("/scan")
def scan():
print("Scanning...")
command = SCANBUDDY_COMMAND + ["scan"]
duplex = request.args.get("duplex", "n") == 'y'
resolution = request.args.get("resolution", None)
if duplex:
print("Duplex: on")
command += ["-d"]
if resolution:
print(f"Res.: {int(resolution)}")
# turning the string to an int and back to a string should clean up the input
command += ["-r", f"{int(resolution)}"]
result = subprocess.run(command, stdout=subprocess.PIPE, text=True)
output = result.stdout.strip()
print("Scanbuddy output: ")
print(output)
return output
# return f"Scanning {'duplex' if duplex == 'y' else ''}..."
@app.route("/dispatch")
def dispatch():
print("Dispatching...")
command = SCANBUDDY_COMMAND + ["dispatch"]
# TODO: implement user
user = request.args.get("user", "")
result = subprocess.run(command, stdout=subprocess.PIPE, text=True)
output = result.stdout.strip()
print("Scanbuddy output: ")
print(output)
return output
@app.route("/unscan")
def unscan():
print("Unscanning...")
command = SCANBUDDY_COMMAND + ["unscan"]
result = subprocess.run(command, stdout=subprocess.PIPE, text=True)
output = result.stdout.strip()
print("Scanbuddy output: ")
print(output)
return output
@app.route("/clean")
def clean():
print("Cleaning...")
command = SCANBUDDY_COMMAND + ["clean"]
result = subprocess.run(command, stdout=subprocess.PIPE, text=True)
output = result.stdout.strip()
print("Scanbuddy output: ")
print(output)
return output
def create_app():
return app
def main():
from waitress import serve
print("Serving scanbuddy on port 5000")
serve(app, host="0.0.0.0", port=5000)
if __name__=='__main__':
main()