Compare commits

..

7 Commits

Author SHA1 Message Date
Luca 37bcf39835 Add .gitkeep to data directory
continuous-integration/drone/push Build is passing Details
2022-08-29 05:10:03 +02:00
Luca d9852762fe Process schedule.json with Python instead of Go templates
continuous-integration/drone/push Build is failing Details
2022-08-29 05:08:36 +02:00
Luca a5002ef8f2 Revert "Experimentally use Debian-based Hugo image"
This reverts commit 6c95231e89.
2022-08-29 00:44:46 +02:00
Luca 6c95231e89 Experimentally use Debian-based Hugo image
continuous-integration/drone/push Build is passing Details
2022-08-29 00:42:29 +02:00
Luca 2585b1fa05 Add schedule
continuous-integration/drone/push Build is passing Details
2022-08-29 00:35:37 +02:00
Luca 961119ad86 Fix height of title row to prevent it from growing very tall 2022-08-29 00:33:46 +02:00
Luca 2463c21096 Fix 'schedule' shortcode when rooms do not have events on all days 2022-08-29 00:32:50 +02:00
7 changed files with 122 additions and 72 deletions

View File

@ -5,6 +5,11 @@ type: docker
name: default name: default
steps: steps:
- name: fetch-schedule
image: python:3.10-alpine
commands:
- bin/fetch_schedule.py
- name: build - name: build
image: klakegg/hugo:ext-alpine-ci image: klakegg/hugo:ext-alpine-ci
when: when:

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
.hugo_build.lock .hugo_build.lock
data/schedule.json
public/ public/
resources/_gen/ resources/_gen/

View File

@ -55,7 +55,7 @@ $timeslot-height: 0.65em;
.schedule-grid { .schedule-grid {
display: grid; display: grid;
grid-auto-rows: $timeslot-height; grid-auto-rows: $timeslot-height;
grid-template-rows: auto; grid-template-rows: 2em;
&.schedule-room { &.schedule-room {
grid-template-columns: 400px; grid-template-columns: 400px;

85
bin/fetch_schedule.py Executable file
View File

@ -0,0 +1,85 @@
#!/usr/bin/env python3
from datetime import datetime, timedelta
from json import dumps, loads
from pathlib import Path
from urllib.request import urlopen
from zoneinfo import ZoneInfo
GRANULARITY = 30
SCHEDULE_URL = 'https://cfp.fairydust.reisen/iger-2022/schedule/export/schedule.json'
TIMEZONE = 'Europe/Berlin'
def parse_duration(s, num_parts):
duration = 0
for t in s.split(':', maxsplit=num_parts-1):
duration *= 60
duration += int(t)
return duration
def main():
with urlopen(SCHEDULE_URL) as f:
data = loads(f.read())
conference = data['schedule']['conference']
rooms = {}
for day in conference['days']:
for room in conference['rooms']:
name = room['name']
if name not in day['rooms']:
continue
if name not in rooms:
rooms[name] = []
rooms[name] += day['rooms'][name]
timezone = ZoneInfo(TIMEZONE)
start_date = None
end_date = None
for _, events in rooms.items():
for event in events:
date = datetime.fromisoformat(event['date']).astimezone(timezone)
if start_date is None or date < start_date:
start_date = date
event['start_date'] = date
date += timedelta(seconds=parse_duration(event['duration'], 2)*60)
if end_date is None or date > end_date:
end_date = date
event['end_date'] = date
timeline = []
timeslot = parse_duration(conference['timeslot_duration'], 2)
for offset in range(0, int((end_date-start_date).total_seconds()), GRANULARITY*60):
date = start_date + timedelta(seconds=offset)
timeline.append({'date': date.strftime('%Y-%m-%d'), 'start': offset//(timeslot*60)+1, 'time': date.strftime('%H:%M')})
out_data = {
'days': [day['date'] for day in conference['days']],
'end_date': end_date.isoformat(timespec='seconds'),
'rooms': {name: [{
'end': int((event['end_date']-start_date).total_seconds())//(timeslot*60)+1,
'end_time': event['end_date'].strftime('%H:%M'),
'speaker': ', '.join(person['public_name'] for person in event['persons']),
'start': int((event['start_date']-start_date).total_seconds())//(timeslot*60)+1,
'start_time': event['start_date'].strftime('%H:%M'),
'title': event['title'],
'url': event['url'],
} for event in events] for name, events in rooms.items()},
'span': GRANULARITY // timeslot,
'start_date': start_date.isoformat(timespec='seconds'),
'timeline': timeline,
'timezone': TIMEZONE,
'version': data['schedule']['version'],
}
with open(Path(__file__).resolve().parent.parent / 'data' / 'schedule.json', 'w') as f:
f.write(dumps(out_data))
if __name__ == '__main__':
main()

12
content/pages/schedule.md Normal file
View File

@ -0,0 +1,12 @@
---
title: "Programm"
slug: "schedule"
menu:
main:
weight: 15
---
Wir werden in den nächsten Tagen nach und nach weitere Programmpunkte veröffentlichen.
Bitte beachtet, dass die zeitliche Planung sich aktuell noch jederzeit ändern kann.
{{<schedule>}}

0
data/.gitkeep Normal file
View File

View File

@ -1,100 +1,47 @@
{{ $data := getJSON (.Get "url") }} {{ with $.Site.Data.schedule }}
{{ with $data.schedule }}
{{ $timeslotDuration := 0 }}
{{ range split .conference.timeslot_duration ":" }}
{{ $timeslotDuration = add (mul $timeslotDuration 60) (int .) }}
{{ end }}
{{ $rooms := dict }}
{{ range $day := .conference.days }}
{{ range $room := $data.schedule.conference.rooms }}
{{ if index $rooms $room.name }}
{{ $rooms = merge $rooms (dict $room.name ((index $rooms $room.name) | append (index $day.rooms .name))) }}
{{ else }}
{{ $rooms = merge $rooms (dict $room.name (index $day.rooms .name)) }}
{{ end }}
{{ end }}
{{ end }}
{{ $events := slice }}
{{ range $rooms }}
{{ with . }}
{{ if $events }}
{{ $events = $events | append . }}
{{ else }}
{{ $events = . }}
{{ end }}
{{ end }}
{{ end }}
{{ $events = sort $events "date" }}
{{ $startDate := time (index $events 0).date }}
{{ $endDate := 0 }}
{{ with index $events (sub (len $events) 1) }}
{{ $lastDuration := 0 }}
{{ range split .duration ":" }}
{{ $lastDuration = add (mul $lastDuration 60) (int .) }}
{{ end }}
{{ $endDate = time (add (time .date).Unix (mul $lastDuration 60)) }}
{{ end }}
<p class="schedule-info"> <p class="schedule-info">
Version: <span class="schedule-version">{{ .version }}</span> Version: <span class="schedule-version">{{ .version }}</span>
<br>Zeitangaben in <span class="schedule-timezone">{{ $startDate.Format "MST" }}</span> <br>Zeitangaben in <span class="schedule-timezone">{{ .timezone }}</span>
</p> </p>
<div class="schedule-days"> <div class="schedule-days">
{{ range .conference.days }} {{ range .days }}
<a href="#{{ .date }}">{{ .date }}</a>&middot; <a href="#{{ . }}">{{ . }}</a>&middot;
{{ end }} {{ end }}
<a href="#">zurück nach oben</a> <a href="#">zurück nach oben</a>
</div> </div>
<div class="schedule"> <div class="schedule">
<div class="schedule-grid schedule-timeline" style="--span: {{ div 30 $timeslotDuration }}"> <div class="schedule-grid schedule-timeline" style="--span: {{ .span }}">
<h3 class="schedule-title"></h3> <h3 class="schedule-title"></h3>
{{ $lastDate := 0 }} {{ $lastDate := "" }}
{{ range seq 1 (div 30 $timeslotDuration) (div ($endDate.Sub $startDate).Minutes $timeslotDuration) }} {{ range .timeline }}
{{ $date := time (add $startDate.Unix (mul (sub . 1) (mul $timeslotDuration 60))) }} <div class="schedule-time" style="--start: {{ .start }}">
<div class="schedule-time" style="--start: {{ . }}"> {{ if ne .date $lastDate }}
{{ if or (not $lastDate) (ne ($date.Format "2006-01-02") ($lastDate.Format "2006-01-02")) }} <div class="schedule-date" id="{{ .date }}">{{ .date }}</div>
<div class="schedule-date" id="{{ $date.Format "2006-01-02" }}">{{ $date.Format "2006-01-02" }}</div>
{{ end }} {{ end }}
{{ $date.Format "15:04" }} {{ .time }}
</div> </div>
{{ $lastDate = $date }} {{ $lastDate = .date }}
{{ end }} {{ end }}
</div> </div>
{{ range sort $data.schedule.conference.rooms "name" }} {{ range $name, $events := .rooms }}
{{ $name := .name }}
{{ $room := index $rooms $name }}
{{ with $room }}
<div class="schedule-grid schedule-room"> <div class="schedule-grid schedule-room">
<h3 class="schedule-title">{{ $name }}</h3> <h3 class="schedule-title">{{ $name }}</h3>
{{ range . }} {{ range $events }}
{{ $start := add (div ((time .date).Sub $startDate).Minutes $timeslotDuration) 1 }} <a class="schedule-event" href="{{ .url }}" style="--start: {{ .start }};--end: {{ .end }}" target="_blank">
{{ $duration := 0 }}
{{ range split .duration ":" }}
{{ $duration = add (mul $duration 60) (int .) }}
{{ end }}
{{ $end := add $start (div $duration $timeslotDuration) }}
<a class="schedule-event" href="{{ .url }}" style="--start: {{ $start }};--end: {{ $end }}" target="_blank">
<div class="schedule-event-time"> <div class="schedule-event-time">
<span>{{ (time .date).Format "15:04" }}</span> <span>{{ .start_time }}</span>
<span>&ndash;</span> <span>&ndash;</span>
<span>{{ (time (int (add $startDate.Unix (mul (sub $end 1) (mul $timeslotDuration 60))))).Format "15:04" }}</span> <span>{{ .end_time }}</span>
</div> </div>
<div class="schedule-event-detail"> <div class="schedule-event-detail">
<h4 class="schedule-title" title="{{ .title }}">{{ .title }}</h4> <h4 class="schedule-title" title="{{ .title }}">{{ .title }}</h4>
{{ $speaker := delimit (apply .persons "index" "." "public_name") ", " }} <p class="schedule-speaker" title="{{ .speaker }}">{{ .speaker }}</p>
<p class="schedule-speaker" title="{{ $speaker }}">{{ $speaker }}</p>
</div> </div>
</a> </a>
{{ end }} {{ end }}
</div> </div>
{{ end }} {{ end }}
{{ end }}
</div> </div>
{{ end }} {{ end }}