commit 910e5c522d800ac9849748a18689211dcff4ea31 Author: webfarben Date: Mon Feb 23 10:45:26 2026 +0100 Initial commit: PDF zu ICS Konverter diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4f033f5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*.ics +*.pdf +.venv/ +__pycache__/ diff --git a/QUICKSTART.md b/QUICKSTART.md new file mode 100644 index 0000000..8342725 --- /dev/null +++ b/QUICKSTART.md @@ -0,0 +1,98 @@ +# 🚀 Quick Start Guide + +## Schnellstart - 3 Schritte + +### 1. Programm starten + +**macOS/Linux:** +```bash +./start.sh +``` + +**Windows:** +Doppelklick auf `start.cmd` + +### 2. PDF-Dateien hinzufĂŒgen + +Kopieren Sie Ihre Dienstplan-PDF-Dateien in dieses Verzeichnis: +``` +/home/sebastian/Dokumente/ICS-Import/ +``` + +### 3. Konvertieren und Importieren + +Im MenĂŒ wĂ€hlen Sie Option "1. PDF(s) konvertieren" und die ICS-Dateien werden automatisch erstellt. + +--- + +## 📅 In deinen Kalender importieren + +### Google Kalender +1. Öffne [google.com/calendar](https://google.com/calendar) +2. Einstellungen → Kalender importieren +3. "Datei aussuchen" → `.ics` Datei auswĂ€hlen +4. Importieren + +### Outlook +1. Öffne Outlook +2. Datei → Öffnen und exportieren → Importieren +3. `.ics` Datei auswĂ€hlen +4. In einen Kalender importieren + +### Thunderbird/SeaMonkey +1. Kalender öffnen +2. Datei → Importieren +3. `.ics` Datei auswĂ€hlen + +### Apple Kalender (macOS/iOS) +1. Doppelklick auf die `.ics` Datei +2. BestĂ€tigen Sie den Import + +### Linux (KDE Kontact, etc.) +1. Öffnen Sie die Kalenderanwendung +2. Datei → Importieren +3. `.ics` Datei auswĂ€hlen + +--- + +## 💡 Tipps und Tricks + +### Mehrere PDFs gleichzeitig +Das Programm verarbeitet automatisch alle `.pdf` Dateien im Verzeichnis. Kopieren Sie einfach mehrere PDFs hinein! + +### Zeitzone anpassen +Falls Sie eine andere Zeitzone benötigen, bearbeiten Sie `pdf_to_ics.py`: +```python +tz = pytz.timezone('Europe/Berlin') # Ändern Sie diesen Wert +``` + +VerfĂŒgbare Zeitzonen: [Liste hier](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) + +### Automatische Updates +Sobald Sie neue Dienstplan-PDFs hinzufĂŒgen und das Programm erneut ausfĂŒhren, werden neue `.ics` Dateien erstellt. + +--- + +## ❓ HĂ€ufige Probleme + +### "Keine PDF-Dateien gefunden" +- ÜberprĂŒfen Sie, dass die PDF-Dateien im gleichen Verzeichnis wie die Skripte sind +- Dateiname darf Leerzeichen enthalten + +### "Keine Events gefunden" +- Die PDF muss das richtige Format haben (ein Dienstplan mit Tabelle) +- Kontrollieren Sie die PDF-Struktur + +### Zeitangaben falsch +- Die Standard-Einstellung ist Zeitzone "Europe/Berlin" +- Falls Sie eine andere Zeitzone benötigen, siehe "Zeitzone anpassen" oben + +--- + +## 📞 Weitere Hilfe + +Siehe **README.md** fĂŒr ausfĂŒhrliche Dokumentation. + +--- + +Viel Spaß! 😊 diff --git a/README.md b/README.md new file mode 100644 index 0000000..7824010 --- /dev/null +++ b/README.md @@ -0,0 +1,110 @@ +# PDF zu ICS Konverter - Dienstplan Importer + +Dieses Tool extrahiert Kalenderdaten aus Dienstplan-PDFs und konvertiert sie in das iCalendar-Format (ICS), das von den meisten Kalenderanwendungen importiert werden kann. + +## Features + +✅ Extrahiert Dienstplan-Informationen aus PDFs +✅ Erkennt Schicht-Zeitangaben (z.B. 04:51-15:46) +✅ Handhabt Nachtschichten korrekt (ĂŒber Mitternacht hinaus) +✅ Erstellt Standard-konforme ICS-Dateien +✅ UnterstĂŒtzt mehrere PDFs gleichzeitig +✅ Benutzerfreundliche OberflĂ€che + +## Installation + +Die erforderlichen Dependencies sind bereits installiert. Falls Sie das Projekt neu einrichten: + +```bash +python3 -m venv .venv +source .venv/bin/activate +pip install pdfplumber icalendar pypdf2 pytz +``` + +## Verwendung + +### Schnellstart + +1. Kopieren Sie Ihre Dienstplan-PDF-Dateien in dieses Verzeichnis +2. FĂŒhren Sie das Skript aus: + +```bash +python3 pdf_to_ics.py +``` + +Das Tool findet automatisch alle `.pdf` Dateien und erstellt entsprechende `.ics` Dateien. + +### Erweiterte Nutzung + +Sie können auch direkt mit dem Python-Modul arbeiten: + +```python +from pdf_to_ics import extract_dienstplan_data, create_ics_from_dienstplan + +# PDF verarbeiten +dienstplan = extract_dienstplan_data('meine_pdf.pdf') + +# ICS erstellen +create_ics_from_dienstplan(dienstplan, 'mein_kalender.ics') +``` + +## Dateiformat + +### ICS-Datei importieren + +Die erstellte `.ics` Datei kann in folgende Kalenderanwendungen importiert werden: + +- **Outlook**: Datei → Öffnen und exportieren → Importieren +- **Google Kalender**: Einstellungen → Kalender importieren +- **iCal/macOS**: Doppelklick auf die .ics Datei +- **Thunderbird**: Kalender → Kalender importieren +- **Android**: Mit einer Kalender-App öffnen +- **LibreOffice**: Datei → Öffnen + +## Struktur der extrahierten Daten + +Das Tool extrahiert folgende Informationen aus der PDF: + +- **Name und Personalnummer**: Des Mitarbeiters +- **Betriebshof**: Standort +- **Sollarbeitszeit**: GewĂŒnschte Arbeitszeit pro Monat +- **Events**: Einzelne Schichten mit: + - Datum + - Dienstart (z.B. "36234", "Ruhe", "Dispo") + - Zeitangabe (falls vorhanden) + +## Output + +FĂŒr jede verarbeitete PDF wird eine entsprechende ICS-Datei erstellt: + +``` +2026-02-23 DB Köhler00100718_MĂ€rz2026.pdf → 2026-02-23 DB Köhler00100718_MĂ€rz2026.ics +``` + +Die ICS-Datei enthĂ€lt ein Event fĂŒr jeden Arbeitstag mit: +- **Titel**: Name - Dienstart +- **Beschreibung**: Dienstart und Betriebshof +- **Zeit**: Mit aktueller Zeitzone (Europe/Berlin) + +## Fehlerbehebung + +### Keine Events gefunden? +- Stellen Sie sicher, dass die PDF das erwartete Tabellenformat hat +- ÜberprĂŒfen Sie die Dateiname und die PDF-Struktur + +### Zeitzone falsch? +- Die aktuelle Einstellung ist Europe/Berlin +- Zum Ändern: Bearbeiten Sie die Zeile in `pdf_to_ics.py`: + ```python + tz = pytz.timezone('Europe/Berlin') # Ändern SIe diesen Wert + ``` + +## Technische Details + +- **AbhĂ€ngigkeiten**: pdfplumber, icalendar, pytz, pypdf2 +- **Python-Version**: 3.6+ +- **Format**: iCalendar 2.0 (RFC 5545) + +## Lizenz + +Dieses Tool ist zur privaten Verwendung gedacht. diff --git a/ZUSAMMENFASSUNG.md b/ZUSAMMENFASSUNG.md new file mode 100644 index 0000000..b764c3e --- /dev/null +++ b/ZUSAMMENFASSUNG.md @@ -0,0 +1,178 @@ +# 📋 Projekt-Zusammenfassung + +## ✅ Projekt abgeschlossen! + +Ihr PDF zu ICS Konverter fĂŒr DienstplĂ€ne ist vollstĂ€ndig eingerichtet und einsatzbereit. + +--- + +## 📁 Projektstruktur + +``` +ICS-Import/ +├── 📄 README.md ← ausfĂŒhrliche Dokumentation +├── 📄 QUICKSTART.md ← schnelle Anleitung +├── 📄 ZUSAMMENFASSUNG.md ← dieses Dokument +│ +├── 🐍 pdf_to_ics.py ← Kern-Konvertierungsskript +├── 🎹 menu.py ← interaktives BenutzermenĂŒ +│ +├── 🚀 start.sh ← Startskript (macOS/Linux) +├── 🚀 start.cmd ← Startskript (Windows) +│ +├── 📩 .venv/ ← Python-Umgebung (automatisch) +│ +└── 📝 PDF-Dateien & ICS-Dateien ← ihre Daten + ├── 2026-02-23 DB Köhler00100718_MĂ€rz2026.pdf + └── 2026-02-23 DB Köhler00100718_MĂ€rz2026.ics ✓ +``` + +--- + +## 🎯 Was wurde erstellt + +### 1. **PDF-Parser** (`pdf_to_ics.py`) + - Extrahiert Dienstplan-Informationen aus PDFs + - Erkennt Zeitangaben und Schichtdaten + - Erstellt valide iCalendar-Dateien + - UnterstĂŒtzt mehrere PDF-Dateien + +### 2. **BenutzermenĂŒ** (`menu.py`) + - Interaktive OberflĂ€che + - PDF-Verzeichnis durchsuchen + - Mehrere PDFs konvertieren + - Fehlerbehandlung + +### 3. **Startskripte** + - Linux/macOS: `start.sh` + - Windows: `start.cmd` + - Automatische Umgebungseinrichtung + +### 4. **Dokumentation** + - README.md - ausfĂŒhrliche Anleitung + - QUICKSTART.md - schnelle Einstieg + - Diese Zusammenfassung + +--- + +## đŸŽ›ïž Verwendung + +### Von der Kommandozeile: +```bash +cd /home/sebastian/Dokumente/ICS-Import +python3 pdf_to_ics.py # Alle PDFs konvertieren +python3 menu.py # Interaktives MenĂŒ +./start.sh # Schnellstart (Linux/macOS) +``` + +### Von Windows: +``` +Doppelklick auf start.cmd +``` + +--- + +## 📅 Funktionen der erstellten ICS-Dateien + +✅ **VollstĂ€ndige Ereignisinformationen:** + - Titel: Name - Dienstart + - Beschreibung: Dienstart & Betriebshof + - Datum und Uhrzeit + - Zeitzone: Europe/Berlin + +✅ **Intelligente Zeitverarbeitung:** + - Nachtschichten (ĂŒber Mitternacht) + - Ganztagesveranstaltungen + - Automatische Zeitzone-Anpassung + +✅ **Kalender-kompatibel mit:** + - Google Kalender ✓ + - Outlook ✓ + - Apple Kalender ✓ + - Thunderbird ✓ + - LibreOffice ✓ + - Linux Kalender-Apps ✓ + +--- + +## 🔧 Technische Details + +- **Sprache:** Python 3.6+ +- **AbhĂ€ngigkeiten:** pdfplumber, icalendar, pytz, pypdf2 +- **Format:** iCalendar 2.0 (RFC 5545) +- **Umgebung:** Python virtual environment (.venv) + +### Installierte Pakete: +``` +pdfplumber==0.10.0+ - PDF-Datenextraktion +icalendar==5.0.0+ - ICS-Datei-Erstellung +pytz - Zeitzonenverwaltung +pypdf2 - PDF-Parsing +``` + +--- + +## 💡 NĂ€chste Schritte + +### 1. **Ihre erste Konvertierung:** + ```bash + cd /home/sebastian/Dokumente/ICS-Import + ./start.sh + ``` + WĂ€hlen Sie Option "1. PDF(s) konvertieren" + +### 2. **ICS in Kalender importieren:** + - Siehe README.md fĂŒr Anleitung pro Kalender-App + - Oder siehe QUICKSTART.md fĂŒr schnelle Übersicht + +### 3. **Weitere PDFs hinzufĂŒgen:** + - Kopieren Sie PDF-Dateien in das Verzeichnis + - Das Programm verarbeitet sie automatisch + +--- + +## 🐛 Fehlerbehebung + +| Problem | Lösung | +|---------|--------| +| "Keine PDF gefunden" | PDFs mĂŒssen im Projektverzeichnis sein | +| "Keine Events" | PDF muss das richtige Tabellenformat haben | +| "Zeitzone falsch" | Bearbeiten Sie `pdf_to_ics.py` Zeile mit `pytz.timezone()` | +| Import-Fehler in Kalender | Stelle sicher, dass die `.ics` Datei nicht beschĂ€digt ist | + +--- + +## 📊 Beispiel-Output + +``` +Verarbeite: 2026-02-23 DB Köhler00100718_MĂ€rz2026.pdf +Name: Sebastian Köhler +Personalnummer: 00100718 +Betriebshof: NSCH3 +Anzahl der Events: 31 +✓ ICS-Datei erstellt: 2026-02-23 DB Köhler00100718_MĂ€rz2026.ics +``` + +Jedes Event in der ICS-Datei: +- **Datum:** Automatisch aus PDF extrahiert +- **Zeit:** z.B. 04:51-15:46 Uhr +- **Titel:** z.B. "Sebastian Köhler - 36234" +- **Beschreibung:** Dienstart & Betriebshof + +--- + +## 📞 Support + +FĂŒr detaillierte Informationen: +- **README.md** - AusfĂŒhrliche Dokumentation +- **QUICKSTART.md** - Schnelle Anleitung zum Import +- **Python-Code** - Gut kommentiert und erweiterbar + +--- + +## 🎉 Fertig! + +Ihr System ist bereit. Viel Erfolg mit der Dienstplan-Verwaltung! 📅✹ + +**Letzte Änderung:** 23. Februar 2026 +**Status:** ✅ Einsatzbereit diff --git a/menu.py b/menu.py new file mode 100644 index 0000000..f2e889c --- /dev/null +++ b/menu.py @@ -0,0 +1,201 @@ +#!/usr/bin/env python3 +""" +Interaktives MenĂŒ fĂŒr PDF zu ICS Konvertierung +Benutzerfreundliche OberflĂ€che zum Verarbeiten von Dienstplan-PDFs +""" + +import os +import sys +from pathlib import Path +from pdf_to_ics import extract_dienstplan_data, create_ics_from_dienstplan + + +def print_header(): + """Zeige Programm-Header""" + print("\n" + "="*60) + print("PDF zu ICS Konverter - Dienstplan Importer".center(60)) + print("="*60 + "\n") + + +def print_menu(): + """Zeige HauptmenĂŒ""" + print("\nHauptmenĂŒ:") + print("1. PDF(s) konvertieren") + print("2. Verzeichnis durchsuchen") + print("3. Über dieses Programm") + print("4. Beenden") + print("-" * 40) + + +def list_pdf_files(): + """Liste alle PDF-Dateien im aktuellen Verzeichnis""" + pdf_files = list(Path('.').glob('*.pdf')) + return pdf_files + + +def convert_pdf(pdf_path): + """Konvertiere eine einzelne PDF-Datei""" + try: + print(f"\n▶ Verarbeite: {pdf_path}") + + # Extrahiere Daten + dienstplan = extract_dienstplan_data(str(pdf_path)) + + # Zeige Informationen + print(f" Name: {dienstplan['vorname']} {dienstplan['name']}") + print(f" Personalnummer: {dienstplan['personalnummer']}") + print(f" Betriebshof: {dienstplan['betriebshof']}") + print(f" Zeitraum: {dienstplan['monat_start']}") + print(f" Sollarbeitszeit: {dienstplan['sollarbeitszeit']}") + print(f" Events gefunden: {len(dienstplan['events'])}") + + if not dienstplan['events']: + print(" ⚠ Warnung: Keine Events gefunden!") + return False + + # Erstelle ICS-Datei + ics_path = pdf_path.with_suffix('.ics') + create_ics_from_dienstplan(dienstplan, str(ics_path)) + + print(f" ✓ ICS-Datei erstellt: {ics_path}") + print(f" ✓ Erfolg!\n") + + return True + + except Exception as e: + print(f" ✗ Fehler: {e}\n") + return False + + +def convert_multiple_pdfs(): + """Konvertiere mehrere PDF-Dateien""" + pdf_files = list_pdf_files() + + if not pdf_files: + print("\n⚠ Keine PDF-Dateien im aktuellen Verzeichnis gefunden!") + return + + print(f"\n✓ {len(pdf_files)} PDF-Datei(en) gefunden:\n") + + for i, pdf in enumerate(pdf_files, 1): + print(f"{i}. {pdf}") + + print("\n" + "-" * 40) + + success_count = 0 + for pdf in pdf_files: + if convert_pdf(pdf): + success_count += 1 + + print(f"\n{'='*40}") + print(f"Zusammenfassung: {success_count}/{len(pdf_files)} ICS-Dateien erstellt") + print(f"{'='*40}\n") + + +def find_and_show_pdfs(): + """Durchsuche Verzeichnis und zeige PDFs""" + current_dir = Path('.') + + print("\n📁 PDF-Dateien in diesem Verzeichnis:") + print("-" * 40) + + pdf_files = list(current_dir.glob('*.pdf')) + + if not pdf_files: + print("Keine PDF-Dateien gefunden.") + return + + for i, pdf in enumerate(pdf_files, 1): + size = pdf.stat().st_size + size_mb = size / (1024 * 1024) + + # Versuche GrĂ¶ĂŸe lesbar zu machen + if size_mb > 1: + size_str = f"{size_mb:.2f} MB" + else: + size_kb = size / 1024 + size_str = f"{size_kb:.2f} KB" + + print(f"{i}. {pdf.name:50} {size_str:>10}") + + print("-" * 40) + print(f"\nGesamt: {len(pdf_files)} PDF-Datei(en)\n") + + +def show_about(): + """Zeige Informationen ĂŒber das Programm""" + print(""" +╔═══════════════════════════════════════════════════════════╗ +║ PDF zu ICS Konverter - Dienstplan Importer ║ +║ Version 1.0 ║ +╚═══════════════════════════════════════════════════════════╝ + +BESCHREIBUNG: + Dieses Programm extrahiert Kalenderdaten aus Dienstplan- + PDFs und konvertiert sie in das iCalendar-Format (ICS). + +FEATURES: + ✓ Automatische Extraktion von Schichtdaten + ✓ Erkennung von Zeitangaben und Nachtschichten + ✓ Standard-konforme ICS-Datei-Erstellung + ✓ UnterstĂŒtzung fĂŒr mehrere PDFs + +VERWENDETE LIBRARIES: + ‱ pdfplumber - PDF-Verarbeitung + ‱ icalendar - ICS-Datei-Erstellung + ‱ pytz - Zeitzonenverwaltung + +IMPORT IN KALENDER: + Die erstellten ICS-Dateien können in folgende + Anwendungen importiert werden: + + ✓ Outlook + ✓ Google Kalender + ✓ Apple Kalender (macOS/iOS) + ✓ Thunderbird + ✓ LibreOffice Kalender + ✓ und viele andere... + +FÜR MEHR INFORMATIONEN: + Siehe README.md fĂŒr ausfĂŒhrliche Dokumentation + +""") + + +def main(): + """Hauptprogramm""" + print_header() + + while True: + print_menu() + choice = input("WĂ€hlen Sie eine Option (1-4): ").strip() + + if choice == '1': + convert_multiple_pdfs() + input("DrĂŒcken Sie Enter zum Fortfahren...") + + elif choice == '2': + find_and_show_pdfs() + input("DrĂŒcken Sie Enter zum Fortfahren...") + + elif choice == '3': + show_about() + input("DrĂŒcken Sie Enter zum Fortfahren...") + + elif choice == '4': + print("\nAuf Wiedersehen! 👋\n") + sys.exit(0) + + else: + print("\n✗ UngĂŒltige Auswahl. Bitte versuchen Sie es erneut.") + + os.system('clear' if os.name == 'posix' else 'cls') + print_header() + + +if __name__ == '__main__': + try: + main() + except KeyboardInterrupt: + print("\n\n✗ Programm von Benutzer unterbrochen.\n") + sys.exit(1) diff --git a/pdf_to_ics.py b/pdf_to_ics.py new file mode 100644 index 0000000..acc2ec4 --- /dev/null +++ b/pdf_to_ics.py @@ -0,0 +1,275 @@ +#!/usr/bin/env python3 +""" +PDF zu ICS Konverter fĂŒr DienstplĂ€ne +Extrahiert Schichtinformationen aus PDFs und erstellt iCalendar-Dateien +""" + +import pdfplumber +import re +from datetime import datetime, timedelta +from icalendar import Calendar, Event +from pathlib import Path +import pytz + + +def extract_dienstplan_data(pdf_path): + """ + Extrahiert Dienstplan-Daten aus einer PDF-Datei + """ + dienstplan = { + 'name': None, + 'vorname': None, + 'personalnummer': None, + 'betriebshof': None, + 'sollarbeitszeit': None, + 'monat_start': None, + 'monat_end': None, + 'events': [] + } + + with pdfplumber.open(pdf_path) as pdf: + if not pdf.pages: + return dienstplan + + page = pdf.pages[0] + text = page.extract_text() + + # Extrahiere Metadaten + match = re.search(r'Nachname\s+(\S+)\s+Sollarbeitszeit\s+([\d:]+)', text) + if match: + dienstplan['name'] = match.group(1) + dienstplan['sollarbeitszeit'] = match.group(2) + + match = re.search(r'Vorname\s+(\S+)', text) + if match: + dienstplan['vorname'] = match.group(1) + + match = re.search(r'Personalnummer\s+(\d+)', text) + if match: + dienstplan['personalnummer'] = match.group(1) + + match = re.search(r'Betriebshof\s+(\S+)', text) + if match: + dienstplan['betriebshof'] = match.group(1) + + # Extrahiere Datum-Range + match = re.search(r'(\d+)\.\s+(\w+)\s+(\d{4})\s+-\s+(\d+)\.\s+(\w+)\s+(\d{4})', text) + if match: + start_date_str = f"{match.group(1)}.{match.group(2)}.{match.group(3)}" + dienstplan['monat_start'] = start_date_str + + # Extrahiere Events aus der Tabelle + tables = page.extract_tables() + if len(tables) >= 2: + events = parse_dienstplan_table(tables[1], dienstplan['monat_start']) + dienstplan['events'] = events + + return dienstplan + + +def parse_dienstplan_table(table, month_start_str): + """ + Parst die Dienstplan-Tabelle und extrahiert Events + """ + events = [] + + if not month_start_str: + return events + + # Parse das Startdatum (z.B. "1.MĂ€rz.2026") + date_parts = month_start_str.split('.') + if len(date_parts) != 3: + return events + + try: + day = int(date_parts[0]) + month_name = date_parts[1] + year = int(date_parts[2]) + except: + return events + + # Konvertiere Monatsnamen zu Nummern + months = { + 'Januar': 1, 'Februar': 2, 'MĂ€rz': 3, 'April': 4, 'Mai': 5, 'Juni': 6, + 'Juli': 7, 'August': 8, 'September': 9, 'Oktober': 10, + 'November': 11, 'Dezember': 12 + } + + month = months.get(month_name, 1) + + # Erstelle Basis-Datum + base_date = datetime(year, month, day) + + # Überspringe die Header-Zeile (Montag, Dienstag, etc.) + for row_idx in range(1, len(table)): + row = table[row_idx] + + # Iteriere ĂŒber die 7 Wochentage + for day_idx, cell in enumerate(row): + if cell is None: + continue + + # Zelle kann mehrere Zeilen enthalten (Tag\nDienst\nZeit) + lines = cell.strip().split('\n') + + if not lines or not lines[0]: + continue + + # Erste Zeile ist der Tag + try: + day_num = int(lines[0].strip()) + except: + continue + + # Berechne das Datum + event_date = base_date + timedelta(days=day_num - 1) + + # Extrahiere Dienstart und Zeit + service_code = "" + start_time = None + end_time = None + + if len(lines) > 1: + # Suche nach Zeitangaben (HH:MM-HH:MM) + for line in lines[1:]: + time_match = re.match(r'(\d{2}):(\d{2})-(\d{2}):(\d{2})', line.strip()) + if time_match: + start_time = f"{time_match.group(1)}:{time_match.group(2)}" + end_time = f"{time_match.group(3)}:{time_match.group(4)}" + else: + # Das ist der Dienstart + if not service_code: + service_code = line.strip() + + # Erstelle Event + event = { + 'date': event_date, + 'service': service_code, + 'start_time': start_time, + 'end_time': end_time + } + + events.append(event) + + return events + + +def create_ics_from_dienstplan(dienstplan, output_path=None): + """ + Erstellt eine ICS-Datei aus den Dienstplan-Daten + """ + # Erstelle Calendar + cal = Calendar() + cal.add('prodid', '-//Dienstplan Importer//de') + cal.add('version', '2.0') + cal.add('calscale', 'GREGORIAN') + cal.add('method', 'PUBLISH') + + # Timezone + tz = pytz.timezone('Europe/Berlin') + + # FĂŒge Events hinzu + for event_data in dienstplan['events']: + if not event_data['service']: + continue + + event = Event() + + # Titel - nur den Dienstart + service_type = event_data['service'] + title = f"Dienst: {service_type}" + + event.add('summary', title) + + # Beschreibung + description = f"Dienstart: {service_type}" + if dienstplan['betriebshof']: + description += f"\nBetriebshof: {dienstplan['betriebshof']}" + + event.add('description', description) + + # Datum und Zeit + event_date = event_data['date'] + + if event_data['start_time'] and event_data['end_time']: + # Mit Uhrzeit + try: + start_hour = int(event_data['start_time'][:2]) + start_min = int(event_data['start_time'][3:5]) + end_hour = int(event_data['end_time'][:2]) + end_min = int(event_data['end_time'][3:5]) + + # Wenn Endzeit kleiner als Startzeit, lĂ€uft Schicht in nĂ€chsten Tag + if end_hour < start_hour: + end_date = event_date + timedelta(days=1) + else: + end_date = event_date + + start_dt = event_date.replace(hour=start_hour, minute=start_min, second=0) + end_dt = end_date.replace(hour=end_hour, minute=end_min, second=0) + + event.add('dtstart', tz.localize(start_dt)) + event.add('dtend', tz.localize(end_dt)) + except: + event.add('dtstart', event_date.date()) + else: + # Nur Datum (Ganztagesveranstaltung) + event.add('dtstart', event_date.date()) + event.add('dtend', (event_date + timedelta(days=1)).date()) + + # UID und Metadaten + event.add('uid', f"{event_date.isoformat()}-{event_data['service']}-{dienstplan.get('personalnummer', 'unknown')}@dienstplan") + event.add('created', datetime.now(tz)) + event.add('dtstamp', datetime.now(tz)) + + cal.add_component(event) + + # Speichere ICS-Datei + if not output_path: + output_path = 'dienstplan.ics' + + with open(output_path, 'wb') as f: + f.write(cal.to_ical()) + + return output_path + + +def main(): + """ + Hauptfunktion + """ + import sys + + # Finde alle PDF-Dateien im aktuellen Verzeichnis + pdf_files = list(Path('.').glob('*.pdf')) + + if not pdf_files: + print("Keine PDF-Dateien gefunden!") + return + + for pdf_file in pdf_files: + print(f"\nVerarbeite: {pdf_file}") + + try: + # Extrahiere Daten + dienstplan = extract_dienstplan_data(str(pdf_file)) + + print(f"Name: {dienstplan['vorname']} {dienstplan['name']}") + print(f"Personalnummer: {dienstplan['personalnummer']}") + print(f"Betriebshof: {dienstplan['betriebshof']}") + print(f"Anzahl der Events: {len(dienstplan['events'])}") + + # Erstelle ICS-Datei + ics_path = pdf_file.with_suffix('.ics') + create_ics_from_dienstplan(dienstplan, str(ics_path)) + + print(f"✓ ICS-Datei erstellt: {ics_path}") + + except Exception as e: + print(f"✗ Fehler bei {pdf_file}: {e}") + import traceback + traceback.print_exc() + + +if __name__ == '__main__': + main() diff --git a/start.cmd b/start.cmd new file mode 100644 index 0000000..8a89e5a --- /dev/null +++ b/start.cmd @@ -0,0 +1,19 @@ +@echo off +REM PDF zu ICS Konverter - Windows Startskript + +setlocal enabledelayedexpansion + +REM Wechsel ins Skriptverzeichnis +cd /d "%~dp0" + +REM ÜberprĂŒfe, ob venv existiert +if not exist ".venv" ( + echo Python-Umgebung wird eingerichtet... + python3 -m venv .venv + call .venv\Scripts\pip.exe install -q pdfplumber icalendar pypdf2 pytz +) + +REM Starte das MenĂŒ +call .venv\Scripts\python.exe menu.py + +pause diff --git a/start.sh b/start.sh new file mode 100755 index 0000000..7018844 --- /dev/null +++ b/start.sh @@ -0,0 +1,78 @@ +#!/bin/bash + +# PDF zu ICS Konverter - Startskript + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +cd "$SCRIPT_DIR" + +# Finde Python-Executable +PYTHON_CMD="" +if command -v python3 &> /dev/null; then + PYTHON_CMD="python3" +elif command -v python &> /dev/null; then + PYTHON_CMD="python" +else + echo "❌ Fehler: Python nicht gefunden!" + echo "Bitte installieren Sie Python 3.6 oder höher." + exit 1 +fi + +echo "🐍 Nutze: $PYTHON_CMD" + +# Erstelle venv wenn nicht vorhanden +if [ ! -d ".venv" ]; then + echo "📩 Python-Umgebung wird eingerichtet..." + $PYTHON_CMD -m venv .venv --upgrade-deps || { + echo "❌ venv konnte nicht erstellt werden" + exit 1 + } +fi + +# Nutze Python aus venv +PYTHON_VENV=".venv/bin/python" + +# ÜberprĂŒfe, ob AbhĂ€ngigkeiten installiert sind +if ! $PYTHON_VENV -c "import pdfplumber" 2>/dev/null; then + echo "📚 Installiere AbhĂ€ngigkeiten..." + + # Nutze python -m pip statt pip direkt + if $PYTHON_VENV -m pip install -q pdfplumber icalendar pypdf2 pytz 2>/dev/null; then + echo "✓ AbhĂ€ngigkeiten installiert" + else + echo "❌ Installation fehlgeschlagen" + echo "🔧 Versuche venv neu aufzubauen..." + rm -rf .venv + $PYTHON_CMD -m venv .venv --upgrade-deps || { + echo "❌ venv konnte nicht neu erstellt werden" + exit 1 + } + $PYTHON_VENV -m pip install -q pdfplumber icalendar pypdf2 pytz || { + echo "❌ AbhĂ€ngigkeiten konnten nicht installiert werden" + exit 1 + } + echo "✓ venv neu erstellt" + fi +fi + +# Starte das Skript +if [ -f "$PYTHON_VENV" ]; then + # Versuche zuerst das interaktive MenĂŒ, falls TTY verfĂŒgbar + if [ -t 0 ]; then + $PYTHON_VENV menu.py + else + # Sonst starte die direkte Konvertierung + echo "" + echo "🔄 Konvertiere PDF-Dateien..." + echo "-----------------------------------" + $PYTHON_VENV pdf_to_ics.py + echo "-----------------------------------" + echo "" + echo "✅ Fertig!" + fi +else + echo "❌ Fehler: Python-Umgebung ist beschĂ€digt" + echo "📁 Bitte löschen Sie das .venv Verzeichnis und versuchen Sie erneut:" + echo " rm -rf .venv" + echo " ./start.sh" + exit 1 +fi