From 056fda8cff8d596e42e80dcdbe5574718d3b8b94 Mon Sep 17 00:00:00 2001 From: Jannover5000r Date: Thu, 3 Jul 2025 14:13:59 +0200 Subject: [PATCH] automatic Logging --- main.go | 190 +++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 174 insertions(+), 16 deletions(-) diff --git a/main.go b/main.go index 1eae65e..9dce08f 100644 --- a/main.go +++ b/main.go @@ -10,8 +10,6 @@ import ( "os" "os/signal" "sort" - - // "strings" "syscall" "time" Untis "untislogger/Bot" @@ -51,25 +49,88 @@ func init() { } func main() { - Untis.Main() //starting API calls function - - //checking for time + //Untis.Main() //starting API calls function| happens in schedule func + //Run() + //Starts logging the timetable for each new Lesson and logs changes + scheduleTimetableUpdate() sigChan := make(chan os.Signal, 1) signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM) log.Println("Program is running. Press Ctrl+C to stop.") //Start logging - Run() + //Run() // Block until we receive a signal <-sigChan log.Println("Shutting down...") } +func isScheduledTime(now time.Time) bool { + scheduled := []string{"07:45", "08:35", "09:35", "10:25", "11:25", "12:15", "13:45", "14:25"} + current := now.Format("15:04") + for _, t := range scheduled { + if t == current { + return true + } + } + return false +} +func scheduleTimetableUpdate() { + var prevData []byte + //run once + Untis.Main() + // Initial read of the file + data, err := os.ReadFile("timetableFilled.json") + if err == nil { + prevData = data + } + + // Ticker for checking timetable changes every hour + hourTicker := time.NewTicker(1 * time.Hour) + go func() { + for range hourTicker.C { + Untis.Main() + data, err := os.ReadFile("timetableFilled.json") + if err != nil { + log.Printf("Error reading timetable: %v", err) + } else if !bytes.Equal(data, prevData) { + log.Println("Timetable file has changed.") + sendUpdateDiscordWebhook() + prevData = data + } + } + }() + + // Ticker for checking scheduled times every minute + startMinuteTicker(func() { + now := time.Now() + if isScheduledTime(now) { + log.Println("Scheduled time reached, updating and running Run()") + Untis.Main() + log.Println("Updated now running Run()") + Run() + log.Println("Finished running Run") + } + }) +} + +func startMinuteTicker(f func()) { + now := time.Now() + next := now.Truncate(time.Minute).Add(time.Minute) + time.Sleep(time.Until(next)) + ticker := time.NewTicker(1 * time.Minute) + go func() { + for { + f() + <-ticker.C + } + }() +} /* #Main Run Function */ func Run() { + log.Println("Sending next Lesson") codeByStartTime, err := MapTimeToCode("timetableFilled.json") if err != nil { log.Println(err) @@ -79,14 +140,25 @@ func Run() { if err != nil { log.Fatal(err) } + subjectByStartTime, err := MapTimeToSubject("timetableFilled.json") + if err != nil { + log.Fatal(err) + } now := time.Now().Format("15:04") nextTime, room, found := NextRoomForTime(roomByStartTime, now) if found { - Status, found := NextCodeForTime(codeByStartTime, now) + log.Println("found Room") + Subject, found := NextSubjectForTime(subjectByStartTime, now) if found { - - fmt.Printf("Next time: %s, Room: %s\n", nextTime, room) - sendDiscordWebhook(room, nextTime, Status) + log.Println("Found Subject") + Status, found := NextCodeForTime(codeByStartTime, now) + if found { + log.Println("Found Status") + fmt.Printf("Next time: %s, Room: %s\n", nextTime, room) + sendDiscordWebhook(Subject, room, nextTime, Status) + } else { + sendDiscordWebhook(Subject, room, nextTime, "") + } } } @@ -118,6 +190,30 @@ func NextRoomForTime(roomByStartTime map[string]string, current string) (string, } return "", "", false } +func NextSubjectForTime(subjectByStartTime map[string]string, current string) (string, bool) { + layout := "15:04" + now, err := time.Parse(layout, current) + if err != nil { + return "", false + } + var times []time.Time + timeToStr := make(map[time.Time]string) + for t := range subjectByStartTime { + parsed, err := time.Parse(layout, t) + if err != nil { + continue + } + times = append(times, parsed) + timeToStr[parsed] = t + } + sort.Slice(times, func(i, j int) bool { return times[i].Before(times[j]) }) + for _, t := range times { + if t.After(now) { + return subjectByStartTime[timeToStr[t]], true + } + } + return "", false +} func NextCodeForTime(codeByStartTime map[string]string, current string) (string, bool) { layout := "15:04" @@ -156,7 +252,9 @@ func MapTimeToRoom(path string) (map[string]string, error) { } roomByStartTime := make(map[string]string) for _, entry := range table { - roomByStartTime[entry.StartTime] = entry.Ro[0] + if len(entry.Ro) > 0 { + roomByStartTime[entry.StartTime] = entry.Ro[0] + } } if roomByStartTime == nil { return nil, nil @@ -175,7 +273,11 @@ func MapTimeToCode(path string) (map[string]string, error) { } codeByStartTime := make(map[string]string) for _, entry := range table { - codeByStartTime[entry.StartTime] = entry.Code + if len(entry.Code) > 0 { + if _, exists := codeByStartTime[entry.StartTime]; !exists { + codeByStartTime[entry.StartTime] = entry.Code + } + } } return codeByStartTime, nil } @@ -191,7 +293,9 @@ func MapTimeToSubject(path string) (map[string]string, error) { } subjectByStartTime := make(map[string]string) for _, entry := range table { - subjectByStartTime[entry.StartTime] = entry.Su[0] + if len(entry.Su) > 0 { + subjectByStartTime[entry.StartTime] = entry.Su[0] + } } return subjectByStartTime, nil } @@ -220,12 +324,12 @@ type Field struct { Inline bool `json:"inline"` } -func sendDiscordWebhook(room string, nextTime string, Status string) { +func sendDiscordWebhook(subject string, room string, nextTime string, Status string) { log.Println("Sending Discord webhook notification...") // Create a rich embed message message := fmt.Sprintf( - "Room: %s\nStart-Time: %s\nStatus: %s", - room, nextTime, Status, + "Subject: %s\nRoom: %s\nStart-Time: %s\nStatus: %s", + subject, room, nextTime, Status, ) /*embed := Embed{ Title: "Next Lesson ", @@ -276,3 +380,57 @@ func sendDiscordWebhook(room string, nextTime string, Status string) { log.Printf("Discord webhook failed with status %d: %s", resp.StatusCode, string(body)) } } + +func sendUpdateDiscordWebhook() { + log.Println("Sending Discord webhook notification...") + // Create a rich embed message + message := "A lesson on your timetable has changed" + /*embed := Embed{ + Title: "Next Lesson ", + Description: "The next lesson is starting soon: ", + Color: 3066993, // Green color + Timestamp: time.Now().Format(time.RFC3339), + Fields: []Field{ + { + Name: "New Lesson", + // Value: fmt.Sprintf("`%s`", ip), + Value: fmt.Sprintf("Room: %s", room), + Inline: true, + }, + { + Name: "Start-Time", + Value: fmt.Sprintf("Start time: %s", nextTime), + Inline: true, + }, + { + Name: "Status", + Value: fmt.Sprintf("Status: %s", Status), + Inline: true, + }, + }, + } + */ + payload := DiscordWebhookPayload{ + Content: message, + } + + jsonData, err := json.Marshal(payload) + if err != nil { + log.Printf("Error marshaling webhook payload: %v", err) + return + } + + resp, err := http.Post(discordWebhookURL, "application/json", bytes.NewBuffer(jsonData)) + if err != nil { + log.Printf("Error sending Discord webhook: %v", err) + return + } + defer resp.Body.Close() + + if resp.StatusCode >= 200 && resp.StatusCode < 300 { + log.Println("Discord webhook notification sent successfully") + } else { + body, _ := ioutil.ReadAll(resp.Body) + log.Printf("Discord webhook failed with status %d: %s", resp.StatusCode, string(body)) + } +}