package main import ( "bytes" "context" "errors" "flag" "fmt" "os" "time" ) func cmdSchedule(ctx context.Context, args []string) error { fs := flag.NewFlagSet("schedule", flag.ContinueOnError) var c commonFlags c.register(fs, "json") season := fs.Int("season", defaultSeason, "season id; see the crawl or leagues command") if err := fs.Parse(args); err != nil { return err } path := SchedulePath(*season) page, err := c.read(ctx, c.client(), path, fmt.Sprintf("season %d", *season)) if errors.Is(err, errUnchanged) { return nil } if err != nil { return err } s, err := ParseSchedule(*season, bytes.NewReader(page)) if err != nil { return err } var b []byte if c.format == "ndjson" { b, err = renderNDJSON(s) } else { b, err = render(c.format, s) } if err != nil { return err } if err := emit(c.out, c.check, b); err != nil { return err } if c.state != "" { if err := saveState(c.state, &state{Path: path, SHA256: sha256Hex(page), LastUpdate: s.LastUpdate, SavedAt: nowStamp()}); err != nil { return err } } if !c.quiet { fmt.Fprintf(os.Stderr, "season %d: %d games, %d played, last update %s\n", s.SeasonID, len(s.Games), s.Played(), s.LastUpdate) } return nil } func cmdLeagues(ctx context.Context, args []string) error { fs := flag.NewFlagSet("leagues", flag.ContinueOnError) var c commonFlags c.register(fs, "json") if err := fs.Parse(args); err != nil { return err } page, err := c.read(ctx, c.client(), "/", "front page") if errors.Is(err, errUnchanged) { return nil } if err != nil { return err } leagues, err := ParseLeagues(bytes.NewReader(page)) if err != nil { return err } var b []byte if c.format == "csv" { var out bytes.Buffer out.WriteString("id,name,path\n") for _, l := range leagues { fmt.Fprintf(&out, "%d,%s,%s\n", l.ID, l.Name, l.Path) } b = out.Bytes() } else { var buf bytes.Buffer enc := jsonEncoder(&buf) if err := enc.Encode(leagues); err != nil { return err } b = buf.Bytes() } return emit(c.out, c.check, b) } // crawlError is what a "record" run emits in place of a season, so a broken // page is a visible hole in the output rather than a missing line. type crawlError struct { SeasonID int `json:"season_id"` Label string `json:"label"` Error string `json:"error"` } func nowStamp() string { return time.Now().UTC().Format(time.RFC3339) }