diff --git a/modules/paperless/default.nix b/modules/paperless/default.nix new file mode 100644 index 00000000..8f32cc3b --- /dev/null +++ b/modules/paperless/default.nix @@ -0,0 +1,42 @@ +{ lib, config, pkgs, ... }: +with lib; +let + psCfg = config.pub-solar; + cfg = config.pub-solar.paperless; + xdg = config.home-manager.users."${psCfg.user.name}".xdg; +in +{ + imports = [ + ./scanbd.nix + ]; + + options.pub-solar.paperless = { + enable = mkEnableOption "All you need to go paperless"; + ocrLanguage = mkOption { + description = "OCR language"; + type = types.str; + example = "eng+deu"; + default = "eng"; + }; + consumptionDir = mkOption { + description = "Directory to be watched"; + type = types.str; + example = "/var/lib/paperless/consume"; + default = "/home/${psCfg.user.name}/Documents"; + }; + }; + + config = mkIf cfg.enable { + services.scanbd.enable = true; + services.paperless-ng = { + enable = true; + consumptionDir = cfg.consumptionDir; + extraConfig = { + PAPERLESS_OCR_LANGUAGE = cfg.ocrLanguage; + }; + }; + environment.systemPackages = [ + pkgs.hplip + ]; + }; +} diff --git a/modules/paperless/scanbd.nix b/modules/paperless/scanbd.nix new file mode 100644 index 00000000..2cf508d4 --- /dev/null +++ b/modules/paperless/scanbd.nix @@ -0,0 +1,176 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + configDir = "/etc/scanbd"; + saneConfigDir = "${configDir}/sane.d"; + cfg = config.pub-solar.paperless; + + scanbdConf = pkgs.writeText "scanbd.conf" + '' + global { + debug = true + debug-level = ${toString config.services.scanbd.debugLevel} + user = ${config.services.scanbd.user} + group = ${config.services.scanbd.group} + scriptdir = ${configDir}/scripts + pidfile = ${config.services.scanbd.pidFile} + timeout = ${toString config.services.scanbd.timeOut} + environment { + device = "SCANBD_DEVICE" + action = "SCANBD_ACTION" + } + + multiple_actions = true + action scan { + numerical-trigger { + from-value = 1 + to-value = 0 + } + desc = "Scan to file" + script = "scan.script" + } + ${config.services.scanbd.extraConfig} + } + ''; + + scanScript = pkgs.writeScript "scanbd_scan.script" + '' + #! ${pkgs.bash}/bin/bash + export PATH=${lib.makeBinPath [ pkgs.coreutils pkgs.sane-frontends pkgs.sane-backends pkgs.ghostscript pkgs.imagemagick ]} + set -x + date="$(date --iso-8601=seconds)" + filename="Scan $date.pdf" + tmpdir="$(mktemp -d)" + exec 3>&1 1>>"/tmp/$filename.log" 2>&1 + pushd "$tmpdir" + scanadf -d "$SCANBD_DEVICE" --resolution 300dpi + + # Convert any PNM images produced by the scan into a PDF with the date as a name + convert image* -density 200 "$filename" + chmod 0666 "$filename" + + # Remove temporary PNM images + rm --verbose image* + + # Atomic move converted PDF to destination directory + paperlessdir="${cfg.consumptionDir}" + cp -pv "$filename" $paperlessdir/"$filename".tmp && + mv $paperlessdir/"$filename".tmp $paperlessdir/"$filename" && + rm "$filename" + + popd + rm -r "$tmpdir" + ''; + +in + +{ + + ###### interface + options = { + + services.scanbd.enable = mkOption { + type = types.bool; + default = false; + description = '' + Enable support for scanbd (scanner button daemon). + + + If scanbd is enabled, then saned must be disabled. + + ''; + }; + + services.scanbd.user = mkOption { + type = types.str; + default = "scanner"; + example = ""; + description = '' + scanbd daemon user name. + ''; + }; + + services.scanbd.group = mkOption { + type = types.str; + default = "scanner"; + example = ""; + description = '' + scanbd daemon group name. + ''; + }; + + services.scanbd.extraConfig = mkOption { + type = types.lines; + default = ""; + example = '' + device canon { + filter = "^genesys.*" + desc = "Canon LIDE" + action file { + filter = "^file.*" + desc = "File" + script = "copy.script" + } + } + ''; + description = '' + Extra configuration lines included verbatim in scanbd.conf. + Use e.g. in lieu of including device-specific config templates + under scanner.d/ + ''; + }; + + services.scanbd.pidFile = mkOption { + type = types.str; + default = "/var/run/scanbd.pid"; + example = ""; + description = '' + PID file path. + ''; + }; + + services.scanbd.timeOut = mkOption { + type = types.int; + default = 500; + example = ""; + description = '' + Device polling timeout (in ms). + ''; + }; + + services.scanbd.debugLevel = mkOption { + type = types.int; + default = 3; + example = ""; + description = '' + Debug logging (1=error, 2=warn, 3=info, 4-7=debug) + ''; + }; + + }; + + ###### implementation + config = mkIf config.services.scanbd.enable { + + users.groups.scanner.gid = config.ids.gids.scanner; + users.users.scanner = { + uid = config.ids.uids.scanner; + group = "scanner"; + }; + + environment.etc."scanbd/scanbd.conf".source = scanbdConf; + environment.etc."scanbd/scripts/scan.script".source = scanScript; + environment.etc."scanbd/scripts/test.script".source = "${pkgs.scanbd}/etc/scanbd/test.script"; + + systemd.services.scanbd = { + enable = true; + description = "Scanner button polling service"; + documentation = [ "https://sourceforge.net/p/scanbd/code/HEAD/tree/releases/1.5.1/integration/systemd/README.systemd" ]; + script = "${pkgs.scanbd}/bin/scanbd -c ${configDir}/scanbd.conf -f"; + wantedBy = [ "multi-user.target" ]; + aliases = [ "dbus-de.kmux.scanbd.server.service" ]; + }; + }; +}