Skip to content

Commit

Permalink
add roomheatmap
Browse files Browse the repository at this point in the history
  • Loading branch information
Raphael Jacob committed Feb 29, 2024
1 parent 94b9343 commit 6808572
Show file tree
Hide file tree
Showing 8 changed files with 390 additions and 15 deletions.
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM golang:1.21
FROM golang:1.22
ADD . /app
WORKDIR /app
RUN go mod vendor
Expand Down
81 changes: 70 additions & 11 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ import (
"fmt"
"github.com/akamensky/argparse"
ics "github.com/arran4/golang-ical"
"github.com/ski7777/asw-stundenplan/pkg/ical"
"github.com/ski7777/asw-stundenplan/pkg/extended_event"
"github.com/ski7777/asw-stundenplan/pkg/roomheatmap"
"github.com/ski7777/asw-stundenplan/pkg/rooms"
"github.com/ski7777/asw-stundenplan/pkg/timetablelist"
"github.com/ski7777/sked-campus-html-parser/pkg/timetable"
"github.com/ski7777/sked-campus-html-parser/pkg/timetablepage"
"github.com/thoas/go-funk"
"log"
Expand All @@ -32,6 +33,9 @@ func main() {
if _, err := os.Stat(*outputdir); os.IsNotExist(err) {
log.Fatalln("output directory does not exist")
}
if err := os.MkdirAll(path.Join(*outputdir, "rooms"), 0755); err != nil {
log.Fatalln(err)
}
tz, err := time.LoadLocation(*timezone)
if err != nil {
log.Fatalln(err)
Expand Down Expand Up @@ -87,7 +91,7 @@ func run(tz *time.Location, outputdir string, motdSummary *string, motdDescripti
threadErrors []error
wg sync.WaitGroup
eventsMutex = &sync.Mutex{}
events = make(map[string]map[string]timetable.Event) //class --> {id --> event}
events = make(map[string]map[string]*extended_event.ExtendedEvent) //class --> {id --> event}
)
log.Println("scraping all timetablepages")
for cn, cttm := range ttm {
Expand All @@ -105,10 +109,10 @@ func run(tz *time.Location, outputdir string, motdSummary *string, motdDescripti
}
eventsMutex.Lock()
defer eventsMutex.Unlock()
var classEvents map[string]timetable.Event
var classEvents map[string]*extended_event.ExtendedEvent
var ok bool
if classEvents, ok = events[cn]; !ok {
classEvents = make(map[string]timetable.Event)
classEvents = make(map[string]*extended_event.ExtendedEvent)
}
defer func() { events[cn] = classEvents }()
for id, e := range ttp.AllEvents {
Expand All @@ -118,7 +122,7 @@ func run(tz *time.Location, outputdir string, motdSummary *string, motdDescripti
threadErrors = append(threadErrors, errors.New(fmt.Sprintf("duplicate event id: class: %s, block: %d, event: %s", cn, bn, id)))
return
}
classEvents[id] = e
classEvents[id] = extended_event.NewExtendedEvent(e, id, cn, tz)
}

}(cn, bn, tturl)
Expand All @@ -136,7 +140,7 @@ func run(tz *time.Location, outputdir string, motdSummary *string, motdDescripti
"scraped %d events for %d classes",
funk.Reduce(
funk.Values(events),
func(acc int, cem map[string]timetable.Event) int {
func(acc int, cem map[string]*extended_event.ExtendedEvent) int {
return acc + len(cem)
},
0,
Expand All @@ -162,7 +166,7 @@ func run(tz *time.Location, outputdir string, motdSummary *string, motdDescripti
}
for cn, ce := range events {
wg.Add(1)
go func(cn string, ce map[string]timetable.Event) {
go func(cn string, ce map[string]*extended_event.ExtendedEvent) {
defer wg.Done()
cal := ics.NewCalendarFor(cn)
cal.SetXPublishedTTL("PT10M")
Expand All @@ -172,9 +176,9 @@ func run(tz *time.Location, outputdir string, motdSummary *string, motdDescripti
cal.SetTimezoneId(tz.String())
cal.SetLastModified(now)
cal.SetProductId(fmt.Sprintf("Stundenplan für die Klasse %s der ASW gGmbH.", cn))
cal.SetDescription("Weitere INformationen zum Stundenplan finden Sie unter https://github.com/ski7777/asw-stundenplan")
for id, e := range ce {
cal.AddVEvent(ical.ConvertEvent(e, id, tz))
cal.SetDescription("Weitere Informationen zum Stundenplan finden Sie unter https://github.com/ski7777/asw-stundenplan")
for _, e := range ce {
cal.AddVEvent(e.ToVEvent())
}
if motd != nil {
cal.AddVEvent(motd)
Expand Down Expand Up @@ -202,5 +206,60 @@ func run(tz *time.Location, outputdir string, motdSummary *string, motdDescripti
}
log.Fatalln("exiting due to errors above")
}
log.Println("generating room heatmaps")
for rhmd := 0; rhmd < 14; rhmd++ {
go func(rhmd int) {
rhmstart := time.Date(
now.Year(),
now.Month(),
now.Day(),
0,
0,
0,
0,
tz,
).Add(time.Hour * 24 * time.Duration(rhmd))
rhmend := rhmstart.Add(time.Hour * 24) // 1 day
rhm := roomheatmap.NewRoomHeatmap(
rhmstart,
rhmend,
time.Minute*15,
rooms.Rooms,
tz,
funk.Reduce(funk.Values(events), func(acc []*extended_event.ExtendedEvent, ae map[string]*extended_event.ExtendedEvent) []*extended_event.ExtendedEvent {
return append(acc, funk.Values(ae).([]*extended_event.ExtendedEvent)...)
}, []*extended_event.ExtendedEvent{}).([]*extended_event.ExtendedEvent),
)
rhm.MinTime = time.Date(0, 0, 0, 8, 0, 0, 0, tz)
rhm.MaxTime = time.Date(0, 0, 0, 20, 0, 0, 0, tz)

af, err := os.Create(path.Join(outputdir, "rooms", fmt.Sprintf("%02d.html", rhmd)))
if err != nil {
threadErrors = append(threadErrors, err)
return
}
defer func(af *os.File) {
_ = af.Close()
}(af)
var rhmhtml string
rhmhtml, err = rhm.GenHTML()
if err != nil {
threadErrors = append(threadErrors, err)
return
}
_, err = af.WriteString(rhmhtml)
if err != nil {
threadErrors = append(threadErrors, err)
return
}
}(rhmd)
}
wg.Wait()
if len(threadErrors) > 0 {
for _, e := range threadErrors {
log.Println(e)
}
log.Fatalln("exiting due to errors above")
}
log.Println("done")
}
4 changes: 1 addition & 3 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
module github.com/ski7777/asw-stundenplan

go 1.21

toolchain go1.21.3
go 1.22.0

require (
github.com/PuerkitoBio/goquery v1.8.1
Expand Down
109 changes: 109 additions & 0 deletions pkg/extended_event/extended_event.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package extended_event

import (
"fmt"
ics "github.com/arran4/golang-ical"
"github.com/ski7777/asw-stundenplan/pkg/rooms"
"github.com/ski7777/sked-campus-html-parser/pkg/timetable"
"github.com/thoas/go-funk"
"strings"
"time"
)

type ExtendedEvent struct {
Event timetable.Event
ID string
Begin, End time.Time
Class string

timezone *time.Location
Summary, Location, Description *string
timeTransparency ics.TimeTransparency
status ics.ObjectStatus
}

func (ee *ExtendedEvent) ToVEvent() *ics.VEvent {
ie := ics.NewEvent(ee.ID)
ie.SetDtStampTime(time.Now())
ie.SetStartAt(ee.Begin)
ie.SetEndAt(ee.End)
if ee.Summary != nil {
ie.SetSummary(*ee.Summary)
}
if ee.Location != nil {
ie.SetLocation(*ee.Location)
}
if ee.Description != nil {
ie.SetDescription(*ee.Description)
}
ie.SetTimeTransparency(ee.timeTransparency)
ie.SetStatus(ee.status)
return ie
}

func (ee *ExtendedEvent) GetRooms() (rl []string) {
rl = []string{}
if ee.Location == nil {
return
}
for _, match := range rooms.RoomRegex.FindAllString(*ee.Location, -1) {
rl = append(rl, match)
}
return
}

func (ee *ExtendedEvent) String() string {
var data = []string{ee.Class}
if ee.Summary != nil {
data = append(data, *ee.Summary+":")
}
data = append(data, ee.Begin.Format("15:04")+"-"+ee.End.Format("15:04"))
if ee.Location != nil {
data = append(data, "Ort:"+*ee.Location)
}
if ee.Description != nil {
data = append(data, *ee.Description)
}
return strings.Join(data, "\n")
}

func NewExtendedEvent(se timetable.Event, id string, cn string, timezone *time.Location) *ExtendedEvent {
ee := &ExtendedEvent{
Event: se,
ID: id,
Class: cn,
timezone: timezone,
Begin: se.Begin.ToTime(se.Date, timezone),
End: se.End.ToTime(se.Date, timezone),
timeTransparency: ics.TransparencyOpaque,
status: ics.ObjectStatusConfirmed,
}
if len(se.Text) > 0 {
ee.Summary = &se.Text[0]
if se.Text[0] == "Reserviert" {
ee.timeTransparency = ics.TransparencyTransparent
ee.status = ics.ObjectStatusTentative
}
}
if len(se.Text) > 1 {
*ee.Summary = fmt.Sprintf("%s (%s)", se.Text[1], se.Text[0])
var locline string
if roomlines := funk.FilterString(se.Text, func(s string) bool {
return strings.HasPrefix(s, "NK: ") || strings.HasPrefix(s, "EXT: ")
}); len(roomlines) > 0 {
locline = roomlines[0]
loc := locline
loc = strings.ReplaceAll(loc, "NK: ", "")
loc = strings.ReplaceAll(loc, "DV ", "")
ee.Location = &loc
}
if desclines := funk.FilterString(se.Text[2:], func(s string) bool {
return s != locline
}); len(desclines) > 0 {
var desc string
desc = strings.Join(desclines, "\n")
ee.Description = &desc
}
}
return ee
}
9 changes: 9 additions & 0 deletions pkg/roomheatmap/html.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package roomheatmap

import _ "embed"
import "html/template"

//go:embed roomheatmap.gohtml
var rhm_template_raw string

var rhm_template = template.Must(template.New("roomheatmap").Parse(rhm_template_raw))
Loading

0 comments on commit 6808572

Please sign in to comment.