Files
pdf-ocr-hotfolder/README.md
T
techadmin 8da0b7da1c fix: veraPDF-FAIL respektiert original_on_success, Logverzeichnis raus (v0.4.1)
- Bei fehlgeschlagener veraPDF-Validierung wurde das Original bisher
  bedingungslos geloescht. Es folgt jetzt derselben
  [output].original_on_success-Regel wie im Erfolgsfall, damit "archive"
  das Original nicht ausgerechnet im Fehlerfall verliert.
- Das nie benutzte Logverzeichnis /var/log/pdf-ocr-hotfolder/ wird nicht
  mehr angelegt; der Dienst loggt ausschliesslich nach journald.
  README und Briefing nennen stattdessen die journalctl-Kommandos.
- 3 neue Tests (95 gesamt)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-22 21:10:27 +02:00

253 lines
9.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# PDF OCR Hotfolder
Verwandelt eingehende gescannte PDFs automatisch in **durchsuchbare PDFs** (PDF/A optional) per OCR. Hauptanwendung: Kunden-Scanner schiebt PDF in einen Ordner — Sekunden später liegt die OCR-Version im Ausgang oder wird in Nextcloud / per SFTP weitergeleitet.
## Features
- 🔍 **OCR via ocrmypdf + Tesseract** (Library-Call, kein Subprozess-Overhead)
- 📂 **Hotfolder via watchdog** — reagiert auf `created`, `moved`, `closed` Events
- 🧠 **Stabilitäts-Erkennung**: wartet bis Scanner fertig geschrieben hat
- 🔁 **Parallelverarbeitung** mehrerer PDFs (ThreadPool, konfigurierbar)
- ✅ **PDF/A-Output** (1, 2 oder 3) optional
- 🛡️ **veraPDF-Validierung** optional
- ☁️ **Upload-Ziele**: lokaler Ordner, Nextcloud (WebDAV via Python), SFTP
- 📧 **E-Mail-Notify** (immer / nur Fehler / nie)
- 🔐 **Service-User-Support** für lokale **und AD-User mit lokaler UID** (SSSD/Winbind)
- ⚙️ Saubere systemd-Integration mit auto-Restart
## Schnellstart
```bash
git clone https://gitea.sonith.de/sonith_ug/pdf-ocr-hotfolder.git
cd pdf-ocr-hotfolder
sudo ./install.sh
```
Der Installer:
1. Installiert einmalig Code + venv + systemd-Template-Unit
2. Fragt nach Instanz-Name, Basis-Pfad, Service-User
3. Legt so viele Hotfolder-Instanzen an, wie du willst (`Weitere Instanz anlegen? [j/N]`)
Bei jedem erneuten Aufruf erkennt der Installer bestehende Instanzen und fragt nur nach neuen.
Test:
```bash
cp irgendein-scan.pdf /var/lib/pdf-ocr-hotfolder/<instanz>/incoming/
journalctl -u pdf-ocr-hotfolder@<instanz> -f
```
Nach wenigen Sekunden liegt das OCR-PDF im `outgoing/`-Ordner der Instanz.
## Multi-Instanz-Betrieb
Das Tool arbeitet komplett **instanzbasiert** über eine systemd Template-Unit `pdf-ocr-hotfolder@<name>.service`. Jede Instanz hat:
- eigene Config-Datei: `/etc/pdf-ocr-hotfolder/<name>.toml`
- eigene Datenverzeichnisse: `/var/lib/pdf-ocr-hotfolder/<name>/{incoming,working,outgoing,error}/`
- eigene systemd-Unit: `pdf-ocr-hotfolder@<name>.service`
- optional eigenen Service-User (via Drop-in `/etc/systemd/system/pdf-ocr-hotfolder@<name>.service.d/user.conf`)
Beispiel für 3 Hotfolder:
```bash
sudo ./install.sh
# → legt z.B. kunde-a, kunde-b, buchhaltung an
systemctl status 'pdf-ocr-hotfolder@*'
journalctl -u pdf-ocr-hotfolder@kunde-a -f
```
Manuell eine weitere Instanz anlegen geht auch — einfach `install.sh` erneut starten, er fragt wieder nach.
## Verzeichnisse
| Pfad | Zweck |
|------|-------|
| `/opt/pdf-ocr-hotfolder/` | Code + venv (für alle Instanzen gemeinsam) |
| `/etc/pdf-ocr-hotfolder/<instanz>.toml` | Config pro Instanz |
| `/etc/systemd/system/pdf-ocr-hotfolder@.service` | systemd Template-Unit |
| `/var/lib/pdf-ocr-hotfolder/<instanz>/incoming` | Eingang (Scanner schreibt hier rein) |
| `/var/lib/pdf-ocr-hotfolder/<instanz>/working` | Arbeitsverzeichnis während OCR |
| `/var/lib/pdf-ocr-hotfolder/<instanz>/outgoing` | Ausgang (fertige PDFs) |
| `/var/lib/pdf-ocr-hotfolder/<instanz>/error` | Fehlgeschlagene PDFs |
| `/var/backups/pdf-ocr-hotfolder/` | Update-Backups |
## Konfiguration
Vollständiges Beispiel: [`config.example.toml`](config.example.toml). Wichtigste Sektionen:
### `[ocr]`
```toml
languages = "deu+eng" # Tesseract-Sprachen
jobs = 4 # Threads pro PDF
skip_text = true # bereits OCR-haltige Seiten überspringen
pdfa_level = "" # "1", "2", "3" oder "" für reines PDF (Default "" wegen Ghostscript-Bug, s.u.)
deskew = true
max_workers = 2 # parallele PDFs
timeout = 300 # max. Sekunden pro SEITE (Tesseract), 0 = ocrmypdf-Default
```
### `[output]`
```toml
# Dateiname im outgoing/:
# "prefix" → OCR_scan.pdf
# "suffix" → scan_OCR.pdf (vor der Extension)
# "none" → scan.pdf (unverändert)
name_mode = "prefix"
name_tag = "OCR_"
# Nach erfolgreichem OCR mit dem Original:
# "delete" → löschen
# "archive" → in archive_dir verschieben
original_on_success = "delete"
archive_dir = "" # absoluter Pfad, Pflicht bei "archive"
```
### `[upload.nextcloud]`
```toml
enabled = true
url = "https://cloud.example.com"
username = "scanuser"
password = "app-password"
remote_path = "Scans/Inbox"
```
### `[upload.sftp]`
```toml
enabled = true
host = "sftp.example.com"
username = "scanuser"
key_file = "/etc/pdf-ocr-hotfolder/sftp_key"
remote_path = "/uploads"
```
### `[notify.email]`
```toml
enabled = true
smtp_host = "smtp.example.com"
smtp_port = 587
smtp_user = "alerts@example.com"
smtp_password = "secret"
from_addr = "PDF OCR <alerts@example.com>"
to_addrs = ["admin@example.com"]
on = "errors" # always | errors | never
```
## Service-Verwaltung
```bash
# Eine bestimmte Instanz
sudo systemctl status pdf-ocr-hotfolder@kunde-a
sudo systemctl restart pdf-ocr-hotfolder@kunde-a
journalctl -u pdf-ocr-hotfolder@kunde-a -f
# Alle Instanzen
sudo systemctl status 'pdf-ocr-hotfolder@*'
sudo systemctl restart 'pdf-ocr-hotfolder@*'
```
### Logs
Der Dienst schreibt **kein eigenes Logfile** — alles geht nach stdout und damit
ins journal:
```bash
journalctl -u pdf-ocr-hotfolder@<instanz> -f # eine Instanz mitlesen
journalctl -u 'pdf-ocr-hotfolder@*' --since today # alle Instanzen, heute
```
## Update
```bash
cd /pfad/zum/repo
git pull
sudo ./update.sh
```
`update.sh`:
1. Stoppt alle laufenden Instanzen
2. Sichert den alten Code nach `/var/backups/pdf-ocr-hotfolder/`
3. Aktualisiert Code + venv + systemd-Template-Unit in `/opt/pdf-ocr-hotfolder/`
4. Startet alle zuvor laufenden Instanzen neu
Config-Dateien unter `/etc/pdf-ocr-hotfolder/` werden **nie** überschrieben.
Das Repo muss bestehen bleiben — `update.sh` kopiert daraus.
## Manueller Lauf (One-Shot)
Bestehende PDFs einer Instanz einmalig verarbeiten und beenden:
```bash
sudo -u pdfocr /opt/pdf-ocr-hotfolder/venv/bin/python -m pdf_ocr_hotfolder \
--config /etc/pdf-ocr-hotfolder/kunde-a.toml --once
```
## Troubleshooting
### Tesseract findet die Sprache nicht
```bash
sudo apt install tesseract-ocr-deu tesseract-ocr-eng
```
### "PriorOcrFoundError"
ocrmypdf erkennt bereits vorhandenen OCR-Text. `skip_text = true` in der Config setzen.
### Berechtigungsprobleme bei AD-User
Service-User braucht **rw** auf alle vier Verzeichnisse unter `/var/lib/pdf-ocr-hotfolder/`. Bei AD-User mit lokaler UID:
```bash
sudo chown -R DOMAIN\\scanuser:DOMAIN\\scangroup /var/lib/pdf-ocr-hotfolder
```
### LXC/Container: Error 226/NAMESPACE
In LXC-Containern schlagen systemd-Hardening-Optionen fehl. Der Installer erkennt Container automatisch und bietet ein Drop-in an. Manuell:
```bash
sudo mkdir -p /etc/systemd/system/pdf-ocr-hotfolder@.service.d/
sudo cp /opt/pdf-ocr-hotfolder/systemd/lxc-compat.conf \
/etc/systemd/system/pdf-ocr-hotfolder@.service.d/
sudo systemctl daemon-reload
sudo systemctl restart 'pdf-ocr-hotfolder@*'
```
### Ghostscript PDF/A-Bug auf Debian 12
GS 10.00.0–10.02.0 (Debian 12 Default) zerstört OCR bei `pdfa_level` + `skip_text=true`. Der Installer bietet automatisch bookworm-backports an. Manuell:
```bash
echo 'deb http://deb.debian.org/debian bookworm-backports main' | \
sudo tee /etc/apt/sources.list.d/bookworm-backports.list
sudo apt update && sudo apt install -t bookworm-backports ghostscript
```
### veraPDF-Validierung schlägt immer fehl
veraPDF binary prüfen (`[verapdf].binary`). Wenn nicht zwingend gebraucht: `enabled = false`.
## Architektur
```
┌──────────┐ watchdog ┌──────────────┐ ocrmypdf ┌──────────┐
│ Scanner │ ──────────────▶ │ incoming/ │ ─────────────▶ │ working/ │
└──────────┘ PDF-Datei └──────────────┘ (Library) └────┬─────┘
│
optional veraPDF
│
▼
┌──────────────┐
│ outgoing/ │
└──────┬───────┘
│
┌──────────────────────┼──────────────────────┐
▼ ▼ ▼
┌────────────┐ ┌────────────┐ ┌────────────┐
│ Nextcloud │ │ SFTP │ │ E-Mail │
│ (WebDAV) │ │ (paramiko) │ │ Notify │
└────────────┘ └────────────┘ └────────────┘
```
## Lizenz
MIT — © Sonith UG
---
**Version:** 0.4.1
**Repo:** https://gitea.sonith.de/sonith_ug/pdf-ocr-hotfolder