- Parse each child's own "Today" day widget for the timetable (FR-16); drop the school-wide week calendar's lesson grid and clean the leaked routine rows. - Add the editable codes map (FR-17): subjects, rooms, teachers and period labels, seeded, an unknown code falls back to the raw code; `school codes` CLI. - Brief: Finn's block first, then Harry's, four sections always present (FR-9); periods decoded into plain English; the undated tail is one counted line (FR-18). - Calendar: write periods + work due + work overdue + major events, per child, on every pass. Identity is the stable per-item key, so a re-run never re-inserts (FR-8). morning-brief.sh now runs scan -> calendar push -> notify. - Day-widget labels are 12-hour: 1-6 read as PM, fixing afternoon periods. Proven live on .13: image 0.6.2-phase6b7b; both children's briefs decoded and separate; 35 events in calendar.school; runs 2 and 3 of the scan added nothing. Co-Authored-By: Paperclip <noreply@paperclip.ing>
55 lines
1.7 KiB
Go
55 lines
1.7 KiB
Go
// Package period understands the Compass lesson label:
|
|
//
|
|
// [period] - [subject code] - [room code] - [teacher initials]
|
|
//
|
|
// for example "1 - 7SCF - H14LAB - KNI". It is a leaf package so the parser,
|
|
// the brief and the calendar all agree on what a routine class period is
|
|
// (AGENTS.md §4 FR-16/FR-17, §7).
|
|
package period
|
|
|
|
import (
|
|
"regexp"
|
|
"strings"
|
|
)
|
|
|
|
// labelRe matches the period part of a lesson label: "5", "C" or
|
|
// "RLE GROUP D". A school event's first part ("End of Year Senior Music
|
|
// Concert") does not match, which is how a lesson is told from an event.
|
|
var labelRe = regexp.MustCompile(`^(\d{1,2}|[A-Z]|RLE GROUP [A-Z])$`)
|
|
|
|
// IsPeriodLabel reports whether s is a period slot rather than an event name.
|
|
func IsPeriodLabel(s string) bool {
|
|
return labelRe.MatchString(strings.TrimSpace(s))
|
|
}
|
|
|
|
// Split breaks a lesson title into its components. ok is false when the first
|
|
// part is not a period label, so the caller renders the title unchanged.
|
|
//
|
|
// A lesson may have fewer than four parts when Compass omits the room or the
|
|
// teacher ("1 - 11HLEGB5 -"), so missing components come back as "".
|
|
func Split(title string) (period, subject, room, teacher string, ok bool) {
|
|
parts := SplitDash(title)
|
|
if len(parts) < 2 || !IsPeriodLabel(parts[0]) {
|
|
return "", "", "", "", false
|
|
}
|
|
period = parts[0]
|
|
subject = parts[1]
|
|
if len(parts) >= 3 {
|
|
room = parts[2]
|
|
}
|
|
if len(parts) >= 4 {
|
|
teacher = parts[3]
|
|
}
|
|
return period, subject, room, teacher, true
|
|
}
|
|
|
|
// SplitDash splits on " - " and trims each part.
|
|
func SplitDash(s string) []string {
|
|
raw := strings.Split(s, " - ")
|
|
out := make([]string, 0, len(raw))
|
|
for _, p := range raw {
|
|
out = append(out, strings.TrimSpace(p))
|
|
}
|
|
return out
|
|
}
|