diff --git a/lektor/docker/entrypoint.sh b/lektor/docker/entrypoint.sh index e3b9c23..e854bad 100644 --- a/lektor/docker/entrypoint.sh +++ b/lektor/docker/entrypoint.sh @@ -14,4 +14,10 @@ tempfile=$(mktemp) sh -c ". /opt/venv/bin/activate && exec python /opt/lektor/scripts/calendar-fetcher-main+fr.py ${CALENDAR_URL} > $tempfile" mv $tempfile /opt/lektor/project/content/contents+fr.lr +sh -c ". /opt/venv/bin/activate && exec python /opt/lektor/scripts/calendar-fetcher+de.py ${CALENDAR_URL} > /opt/lektor/project/content/termine/contents+de.lr" +# TODO As the file reads from the same file as it's output is afterwards piped into this leads to synchronization/buffering issues, we therefore write to a temporaray file and move it to the right place in a subsequent step +tempfile=$(mktemp) +sh -c ". /opt/venv/bin/activate && exec python /opt/lektor/scripts/calendar-fetcher-main+de.py ${CALENDAR_URL} > $tempfile" +mv $tempfile /opt/lektor/project/content/contents+de.lr + exec "$@" \ No newline at end of file diff --git a/lektor/lektordata/project/content/contents+de.lr b/lektor/lektordata/project/content/contents+de.lr new file mode 100644 index 0000000..56ccee2 --- /dev/null +++ b/lektor/lektordata/project/content/contents+de.lr @@ -0,0 +1,29 @@ +_model: htmlpage +--- +title: Willkommen beim PC Stammertal +--- +html: + +

Unser nächster Anlass:


+
Montag 1. September 18:30, freies Training, Stammheim
+
+  
+  
+  
+
+
+
+ Terminkalender All unsere Termine +
+
+ Buch Alle Infos über uns +
+
+ Briefe Kontaktiere uns +
+
+--- +_template: + +page.html + diff --git a/lektor/lektordata/project/content/contents+fr.lr b/lektor/lektordata/project/content/contents+fr.lr index 0282f32..6560fea 100644 --- a/lektor/lektordata/project/content/contents+fr.lr +++ b/lektor/lektordata/project/content/contents+fr.lr @@ -5,14 +5,12 @@ title: Bienvenue au PC Stammertal html:

Notre prochain événement:


-
samedi 22. mars 9:00, Frühlingsschiessen, Bülach
+
lundi 1. septembre 18:30, freies Training, Stammheim
 
 
 
-

...et ne manquez pas non plus :

-27. Zürcher Kantonalschützenfest 2025
Calendrier Tous nos événements diff --git a/lektor/lektordata/project/content/contents.lr b/lektor/lektordata/project/content/contents.lr index 6bd5928..56ccee2 100644 --- a/lektor/lektordata/project/content/contents.lr +++ b/lektor/lektordata/project/content/contents.lr @@ -5,14 +5,12 @@ title: Willkommen beim PC Stammertal html:

Unser nächster Anlass:


-
Samstag 22. März 9:00, Frühlingsschiessen, Bülach
+
Montag 1. September 18:30, freies Training, Stammheim
 
 
 
-

...und auch nicht verpassen:

-27. Zürcher Kantonalschützenfest 2025
Terminkalender All unsere Termine diff --git a/lektor/lektordata/project/content/termine/contents+de.lr b/lektor/lektordata/project/content/termine/contents+de.lr new file mode 100644 index 0000000..86d095b --- /dev/null +++ b/lektor/lektordata/project/content/termine/contents+de.lr @@ -0,0 +1,79 @@ +_model: page +--- +title: Termine +--- +body: + +*
freies Training
  + *
Mo. 1. September 2025
  + *
18:30
  + *
Stammheim
  +*
Kreismatch
  + *
Mo. 8. September 2025
  + *
18:00
  + *
Stammheim
  +*
Orientierungslauf Stammerberg (kein Schiessbetrieb!)
  + *
Sa. 13. September 2025
  + *
 
  + *
Unterstammheim
  +*
Kreismatch
  + *
Mo. 15. September 2025
  + *
18:00
  + *
Stammheim
  +*
Schwaderlohschiessen
  + *
Sa. 20. September 2025
  + *
13:30
  + *
Alterswilen
  +*
freies Training
  + *
Mo. 22. September 2025
  + *
18:00
  + *
Stammheim
  +*
Schwaderlohschiessen (unser Schiesstag)
  + *
Di. 23. September 2025
  + *
17:30
  + *
Alterswilen
  +*
Schwaderlohschiessen
  + *
Sa. 27. September 2025
  + *
8:00
  + *
Alterswilen
  +*
Schwaderlohschiessen
  + *
So. 28. September 2025
  + *
10:00
  + *
Alterswilen
  +*
Endschiessen
  + *
Mo. 29. September 2025
  + *
17:00
  + *
Stammheim
  +*
Endschiessen
  + *
Mo. 6. Oktober 2025
  + *
17:00
  + *
Stammheim
  +*
Niklausschiessen
  + *
Sa. 25. Oktober 2025
  + *
9:00
  + *
Diessenhofen
  +*
Niklausschiessen
  + *
So. 26. Oktober 2025
  + *
9:00
  + *
Diessenhofen
  +*
Absenden
  + *
Fr. 31. Oktober 2025
  + *
19:00
  + *
 
  +*
Niklausschiessen
  + *
Sa. 1. November 2025
  + *
9:00
  + *
Diessenhofen
  +*
Appenzeller Lupi Meisterschaft
  + *
So. 11. Januar 2026
  + *
9:00
  + *
 
  +*
Generalversammlung
  + *
Do. 5. Februar 2026
  + *
19:00
  + *
 
  + +--- +_template: page.html + + diff --git a/lektor/lektordata/project/content/termine/contents+fr.lr b/lektor/lektordata/project/content/termine/contents+fr.lr index cd5d7c2..511696e 100644 --- a/lektor/lektordata/project/content/termine/contents+fr.lr +++ b/lektor/lektordata/project/content/termine/contents+fr.lr @@ -4,178 +4,6 @@ title: Événements --- body: -*
Frühlingsschiessen
  - *
sam. 22. mars 2025
  - *
9:00
  - *
Bülach
  -*
Standreinigung
  - *
sam. 22. mars 2025
  - *
9:00
  - *
 
  -*
freies Training
  - *
lun. 31. mars 2025
  - *
18:00
  - *
Stammheim
  -*
Eulachschiessen
  - *
ven. 4. avril 2025
  - *
16:00
  - *
Winterthur
  -*
Eulachschiessen
  - *
sam. 5. avril 2025
  - *
8:30
  - *
Winterthur
  -*
Eulachschiessen
  - *
ven. 11. avril 2025
  - *
16:00
  - *
Winterthur
  -*
Eulachschiessen
  - *
sam. 12. avril 2025
  - *
8:30
  - *
Winterthur
  -*
Kreis Winterschiessen
  - *
lun. 14. avril 2025
  - *
18:00
  - *
Stammheim
  -*
Obligatorisches Programm und Kreis Winterschiessen
  - *
lun. 28. avril 2025
  - *
18:00
  - *
Stammheim
  -*
freies Training
  - *
lun. 5. mai 2025
  - *
18:30
  - *
Stammheim
  -*
freies Training
  - *
lun. 12. mai 2025
  - *
18:30
  - *
Stammheim
  -*
Schlossschiessen
  - *
jeu. 15. mai 2025
  - *
17:30
  - *
Wülflingen
  -*
Schlossschiessen
  - *
ven. 16. mai 2025
  - *
17:30
  - *
Wülflingen
  -*
Schlossschiessen
  - *
sam. 17. mai 2025
  - *
9:30
  - *
Wülflingen
  -*
Obligatorisches Programm und freies Training
  - *
lun. 19. mai 2025
  - *
18:30
  - *
Stammheim
  -*
Schlossschiessen
  - *
jeu. 22. mai 2025
  - *
17:30
  - *
Wülflingen
  -*
Schlossschiessen
  - *
ven. 23. mai 2025
  - *
17:30
  - *
Wülflingen
  -*
freies Training
  - *
lun. 26. mai 2025
  - *
18:30
  - *
Stammheim
  -*
Kreis Sommerschiessen
  - *
lun. 2. juin 2025
  - *
18:30
  - *
Stammheim
  -*
Sommer-Schüsse
  - *
ven. 6. juin 2025
  - *
17:00
  - *
Rafz
  -*
Sommer-Schüsse
  - *
sam. 14. juin 2025
  - *
9:00
  - *
Rafz
  -*
Obligatorisches Programm und freies Training
  - *
lun. 16. juin 2025
  - *
18:30
  - *
Stammheim
  -*
freies Training
  - *
lun. 23. juin 2025
  - *
18:30
  - *
Stammheim
  -*
freies Training
  - *
lun. 30. juin 2025
  - *
18:30
  - *
Stammheim
  -*
Bezirks Sommerschiessen
  - *
sam. 5. juillet 2025
  - *
17:00
  - *
Flurlingen
  -*
freies Training
  - *
lun. 7. juillet 2025
  - *
18:30
  - *
Stammheim
  -*
Terassenfest
  - *
ven. 11. juillet 2025
  - *
19:00
  - *
Stammheim
  -*
Bezirks Sommerschiessen
  - *
sam. 12. juillet 2025
  - *
14:00
  - *
Flurlingen
  -*
freies Training
  - *
lun. 14. juillet 2025
  - *
18:30
  - *
Stammheim
  -*
Obligatorisches Programm und freies Training
  - *
lun. 11. août 2025
  - *
18:30
  - *
Stammheim
  -*
ZHKSF Ausbildung Pistole
  - *
jeu. 14. août 2025
  - *
18:30
  - *
 
  -*
Zürcher Kantonalschützenfest
  - *
ven. 15. août 2025
  - *
 
  - *
 
  -*
Zürcher Kantonalschützenfest
  - *
sam. 16. août 2025
  - *
 
  - *
 
  -*
Zürcher Kantonalschützenfest
  - *
dim. 17. août 2025
  - *
 
  - *
 
  -*
KEIN Training
  - *
lun. 18. août 2025
  - *
 
  - *
 
  -*
ZHKSF intern
  - *
jeu. 21. août 2025
  - *
18:30
  - *
 
  -*
Zürcher Kantonalschützenfest
  - *
ven. 22. août 2025
  - *
 
  - *
 
  -*
Zürcher Kantonalschützenfest
  - *
sam. 23. août 2025
  - *
 
  - *
 
  -*
Zürcher Kantonalschützenfest
  - *
dim. 24. août 2025
  - *
 
  - *
 
  -*
Zürcher Kantonalschützenfest
  - *
lun. 25. août 2025
  - *
 
  - *
 
  -*
Zürcher Kantonalschützenfest
  - *
ven. 29. août 2025
  - *
 
  - *
 
  -*
Zürcher Kantonalschützenfest
  - *
sam. 30. août 2025
  - *
 
  - *
 
  -*
Zürcher Kantonalschützenfest
  - *
dim. 31. août 2025
  - *
 
  - *
 
  *
freies Training
  *
lun. 1. septembre 2025
  *
18:30
  diff --git a/lektor/lektordata/project/content/termine/contents.lr b/lektor/lektordata/project/content/termine/contents.lr index 2c9abea..86d095b 100644 --- a/lektor/lektordata/project/content/termine/contents.lr +++ b/lektor/lektordata/project/content/termine/contents.lr @@ -4,178 +4,6 @@ title: Termine --- body: -*
Frühlingsschiessen
  - *
Sa. 22. März 2025
  - *
9:00
  - *
Bülach
  -*
Standreinigung
  - *
Sa. 22. März 2025
  - *
9:00
  - *
 
  -*
freies Training
  - *
Mo. 31. März 2025
  - *
18:00
  - *
Stammheim
  -*
Eulachschiessen
  - *
Fr. 4. April 2025
  - *
16:00
  - *
Winterthur
  -*
Eulachschiessen
  - *
Sa. 5. April 2025
  - *
8:30
  - *
Winterthur
  -*
Eulachschiessen
  - *
Fr. 11. April 2025
  - *
16:00
  - *
Winterthur
  -*
Eulachschiessen
  - *
Sa. 12. April 2025
  - *
8:30
  - *
Winterthur
  -*
Kreis Winterschiessen
  - *
Mo. 14. April 2025
  - *
18:00
  - *
Stammheim
  -*
Obligatorisches Programm und Kreis Winterschiessen
  - *
Mo. 28. April 2025
  - *
18:00
  - *
Stammheim
  -*
freies Training
  - *
Mo. 5. Mai 2025
  - *
18:30
  - *
Stammheim
  -*
freies Training
  - *
Mo. 12. Mai 2025
  - *
18:30
  - *
Stammheim
  -*
Schlossschiessen
  - *
Do. 15. Mai 2025
  - *
17:30
  - *
Wülflingen
  -*
Schlossschiessen
  - *
Fr. 16. Mai 2025
  - *
17:30
  - *
Wülflingen
  -*
Schlossschiessen
  - *
Sa. 17. Mai 2025
  - *
9:30
  - *
Wülflingen
  -*
Obligatorisches Programm und freies Training
  - *
Mo. 19. Mai 2025
  - *
18:30
  - *
Stammheim
  -*
Schlossschiessen
  - *
Do. 22. Mai 2025
  - *
17:30
  - *
Wülflingen
  -*
Schlossschiessen
  - *
Fr. 23. Mai 2025
  - *
17:30
  - *
Wülflingen
  -*
freies Training
  - *
Mo. 26. Mai 2025
  - *
18:30
  - *
Stammheim
  -*
Kreis Sommerschiessen
  - *
Mo. 2. Juni 2025
  - *
18:30
  - *
Stammheim
  -*
Sommer-Schüsse
  - *
Fr. 6. Juni 2025
  - *
17:00
  - *
Rafz
  -*
Sommer-Schüsse
  - *
Sa. 14. Juni 2025
  - *
9:00
  - *
Rafz
  -*
Obligatorisches Programm und freies Training
  - *
Mo. 16. Juni 2025
  - *
18:30
  - *
Stammheim
  -*
freies Training
  - *
Mo. 23. Juni 2025
  - *
18:30
  - *
Stammheim
  -*
freies Training
  - *
Mo. 30. Juni 2025
  - *
18:30
  - *
Stammheim
  -*
Bezirks Sommerschiessen
  - *
Sa. 5. Juli 2025
  - *
17:00
  - *
Flurlingen
  -*
freies Training
  - *
Mo. 7. Juli 2025
  - *
18:30
  - *
Stammheim
  -*
Terassenfest
  - *
Fr. 11. Juli 2025
  - *
19:00
  - *
Stammheim
  -*
Bezirks Sommerschiessen
  - *
Sa. 12. Juli 2025
  - *
14:00
  - *
Flurlingen
  -*
freies Training
  - *
Mo. 14. Juli 2025
  - *
18:30
  - *
Stammheim
  -*
Obligatorisches Programm und freies Training
  - *
Mo. 11. August 2025
  - *
18:30
  - *
Stammheim
  -*
ZHKSF Ausbildung Pistole
  - *
Do. 14. August 2025
  - *
18:30
  - *
 
  -*
Zürcher Kantonalschützenfest
  - *
Fr. 15. August 2025
  - *
 
  - *
 
  -*
Zürcher Kantonalschützenfest
  - *
Sa. 16. August 2025
  - *
 
  - *
 
  -*
Zürcher Kantonalschützenfest
  - *
So. 17. August 2025
  - *
 
  - *
 
  -*
KEIN Training
  - *
Mo. 18. August 2025
  - *
 
  - *
 
  -*
ZHKSF intern
  - *
Do. 21. August 2025
  - *
18:30
  - *
 
  -*
Zürcher Kantonalschützenfest
  - *
Fr. 22. August 2025
  - *
 
  - *
 
  -*
Zürcher Kantonalschützenfest
  - *
Sa. 23. August 2025
  - *
 
  - *
 
  -*
Zürcher Kantonalschützenfest
  - *
So. 24. August 2025
  - *
 
  - *
 
  -*
Zürcher Kantonalschützenfest
  - *
Mo. 25. August 2025
  - *
 
  - *
 
  -*
Zürcher Kantonalschützenfest
  - *
Fr. 29. August 2025
  - *
 
  - *
 
  -*
Zürcher Kantonalschützenfest
  - *
Sa. 30. August 2025
  - *
 
  - *
 
  -*
Zürcher Kantonalschützenfest
  - *
So. 31. August 2025
  - *
 
  - *
 
  *
freies Training
  *
Mo. 1. September 2025
  *
18:30
  diff --git a/lektor/lektordata/scripts/calendar-fetcher+de.py b/lektor/lektordata/scripts/calendar-fetcher+de.py new file mode 100644 index 0000000..eb401e6 --- /dev/null +++ b/lektor/lektordata/scripts/calendar-fetcher+de.py @@ -0,0 +1,57 @@ +from datetime import datetime, date, timezone +import locale +import sys +from calendarstuff import get_events + + +def fetch_upcoming_events(ics_url): + + events = get_events(ics_url, 'de_DE.UTF-8') + + for event in events: + + start = event.get('dtstart').dt + out_summary = event.get('summary') + location = event.get('location', 'No location specified') + + out_startdate = start.strftime("%a. %-d. %B %Y") + + # Format output based on whether it's an all-day event + if isinstance(start, date) and not isinstance(start, datetime): + out_starttime = " " + else: + out_starttime = start.strftime('%-H:%M') + + if location != 'No location specified': + out_location = location + else: + out_location = " " + + print(f"*
{out_summary}
 ") + print(f" *
{out_startdate}
 ") + print(f" *
{out_starttime}
 ") + print(f" *
{out_location}
 ") + + +if __name__ == "__main__": + + ics_url = sys.argv[1] + + # ics_url = "https://backoffice.pc-stammertal.ch/remote.php/dav/public-calendars/RqLX5wj25aY6cpnP?export" + + print("_model: page") + print("---") + print("title: Termine") + print("---") + print("body:") + print("") + # print("
Kalender Abonnieren
") + # print("") + # print("
\"Link
") + # print("") + fetch_upcoming_events(ics_url) + print("") + print("---") + print("_template: page.html") + print("") + print("") \ No newline at end of file diff --git a/lektor/lektordata/scripts/calendar-fetcher-main+de.py b/lektor/lektordata/scripts/calendar-fetcher-main+de.py new file mode 100644 index 0000000..c447984 --- /dev/null +++ b/lektor/lektordata/scripts/calendar-fetcher-main+de.py @@ -0,0 +1,140 @@ +#!/usr/bin/env python3 + +import sys +from pathlib import Path +from datetime import datetime, date, timezone +from typing import Optional, NamedTuple +from dataclasses import dataclass +from bs4 import BeautifulSoup +import locale +from calendarstuff import get_events + + +@dataclass +class EventDetails: + weekday: str + date: str + time: str + summary: str + location: str + + def to_html(self) -> str: + return ( + f'
{self.weekday} ' + f'{self.date}{self.time}, {self.summary}' + f'{self.location}
' + ) + +class EventProcessor: + def __init__(self, ics_url: str, content_file: str): + self.ics_url = ics_url + self.content_file = Path(content_file) + self.fallback_html = ( + '
Leider unbekannt, aber ' + 'frag mal den Vorstand der müsste es wissen
' + ) + + @property + def fallback_content(self) -> str: + return f"""_model: htmlpage +--- +title: Willkommen beim PC Stammertal +--- +html: + +

Unser nächster Anlass:


+{self.fallback_html} +
+  
+  
+  
+
+ +--- +_template: + +page.html +""" + + def setup_locale(self) -> None: + try: + locale.setlocale(locale.LC_TIME, 'de_DE.UTF-8') + except locale.Error as e: + print(f"Warning: Failed to set locale: {e}", file=sys.stderr) + + def format_event_time(self, start: datetime | date) -> str: + return "" if isinstance(start, date) and not isinstance(start, datetime) else start.strftime(" %-H:%M") + + def get_next_event(self) -> Optional[EventDetails]: + try: + + events = get_events(self.ics_url, 'de_DE.UTF-8') + + event = events[0] + start = event.get('dtstart').dt + + return EventDetails( + weekday=start.strftime("%A"), + date=start.strftime("%-d. %B"), + time=self.format_event_time(start), + summary=event.get('summary', ''), + location=f", {event.get('location')}" if event.get('location') else "" + ) + + except (StopIteration, AttributeError) as e: + print(f"No upcoming events found: {e}", file=sys.stderr) + return None + + def read_current_content(self) -> tuple[str, str]: + try: + content = self.content_file.read_text() + soup = BeautifulSoup(content, 'html.parser') + events = soup.find_all('div', {'class': 'nextevent'}) + return content, str(events[0]) if len(events) == 1 else "" + + except (IOError, IndexError) as e: + print(f"Error reading content file: {e}", file=sys.stderr) + return "", "" + + def process(self) -> str: + self.setup_locale() + + content, source_str = self.read_current_content() + if not content: + return self.fallback_content + + if len(source_str) > 0 and source_str in content: + event = self.get_next_event() + if not event: + return content.replace(source_str, self.fallback_html).rstrip() + + return content.replace(source_str, event.to_html()).rstrip() + + return self.fallback_content + +def main() -> None: + if len(sys.argv) != 2: + print(f"Usage: {sys.argv[0]} ", file=sys.stderr) + sys.exit(1) + + processor = EventProcessor( + ics_url=sys.argv[1], + content_file="/opt/lektor/project/content/contents+de.lr" + ) + + print(processor.process(), end='') + print("") + print("") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/lektor/lektordata/scripts/calendar-fetcher-main+fr.py b/lektor/lektordata/scripts/calendar-fetcher-main+fr.py index 66978dd..271dc87 100644 --- a/lektor/lektordata/scripts/calendar-fetcher-main+fr.py +++ b/lektor/lektordata/scripts/calendar-fetcher-main+fr.py @@ -49,8 +49,6 @@ html:  
 
-

...et ne manquez pas non plus :

-27. Zürcher Kantonalschützenfest 2025