refactor: reduce cyclomatic complexity in fetchWeekAPI

This commit is contained in:
2026-06-11 12:13:22 +02:00
parent 03ccd54c85
commit ca957b5cdc

View File

@@ -389,6 +389,32 @@ func fetchWeekAPI(ctx context.Context, httpClient *http.Client, token string, ye
return WeekSchedule{}, err return WeekSchedule{}, err
} }
payload, err := fetchWeekAPIPayload(ctx, client, token, year, week, location)
if err != nil {
return WeekSchedule{}, err
}
resolvedYear, resolvedWeek := resolveRequestedISOWeek(year, week)
out := WeekSchedule{
Year: resolvedYear,
Week: resolvedWeek,
Days: map[time.Weekday][]Entry{},
}
for _, item := range payload {
entry, ok := weekEntryFromAPI(item, location)
if !ok {
continue
}
out.Days[entry.Weekday] = append(out.Days[entry.Weekday], entry)
}
return out, nil
}
func fetchWeekAPIPayload(ctx context.Context, client *http.Client, token string, year int, week int, location *time.Location) ([]timetableAnimeAPI, error) {
u, _ := url.Parse("https://animeschedule.net/api/v3/timetables/sub") u, _ := url.Parse("https://animeschedule.net/api/v3/timetables/sub")
q := u.Query() q := u.Query()
if year > 0 && week > 0 { if year > 0 && week > 0 {
@@ -400,7 +426,7 @@ func fetchWeekAPI(ctx context.Context, httpClient *http.Client, token string, ye
req, err := http.NewRequestWithContext(ctx, http.MethodGet, u.String(), nil) req, err := http.NewRequestWithContext(ctx, http.MethodGet, u.String(), nil)
if err != nil { if err != nil {
return WeekSchedule{}, fmt.Errorf("create api request: %w", err) return nil, fmt.Errorf("create api request: %w", err)
} }
req.Header.Set("Authorization", "Bearer "+token) req.Header.Set("Authorization", "Bearer "+token)
req.Header.Set("Accept", "application/json") req.Header.Set("Accept", "application/json")
@@ -408,13 +434,13 @@ func fetchWeekAPI(ctx context.Context, httpClient *http.Client, token string, ye
res, err := client.Do(req) res, err := client.Do(req)
if err != nil { if err != nil {
return WeekSchedule{}, fmt.Errorf("api request failed: %w", err) return nil, fmt.Errorf("api request failed: %w", err)
} }
defer func() { _ = res.Body.Close() }() defer func() { _ = res.Body.Close() }()
if res.StatusCode != http.StatusOK { if res.StatusCode != http.StatusOK {
body, _ := io.ReadAll(io.LimitReader(res.Body, netutil.Bytes512)) body, _ := io.ReadAll(io.LimitReader(res.Body, netutil.Bytes512))
return WeekSchedule{}, &HTTPStatusError{ return nil, &HTTPStatusError{
StatusCode: res.StatusCode, StatusCode: res.StatusCode,
URL: u.String(), URL: u.String(),
ContentType: strings.TrimSpace(res.Header.Get("Content-Type")), ContentType: strings.TrimSpace(res.Header.Get("Content-Type")),
@@ -424,72 +450,64 @@ func fetchWeekAPI(ctx context.Context, httpClient *http.Client, token string, ye
var payload []timetableAnimeAPI var payload []timetableAnimeAPI
if err := json.NewDecoder(res.Body).Decode(&payload); err != nil { if err := json.NewDecoder(res.Body).Decode(&payload); err != nil {
return WeekSchedule{}, fmt.Errorf("decode timetables api: %w", err) return nil, fmt.Errorf("decode timetables api: %w", err)
} }
resolvedYear := year return payload, nil
resolvedWeek := week }
if resolvedYear == 0 || resolvedWeek == 0 {
resolvedYear, resolvedWeek = time.Now().In(time.Local).ISOWeek() func resolveRequestedISOWeek(year int, week int) (int, int) {
} if year > 0 && week > 0 {
return year, week
out := WeekSchedule{ }
Year: resolvedYear,
Week: resolvedWeek, return time.Now().In(time.Local).ISOWeek()
Days: map[time.Weekday][]Entry{}, }
}
func weekEntryFromAPI(item timetableAnimeAPI, location *time.Location) (Entry, bool) {
for _, item := range payload { title := strings.TrimSpace(item.English)
title := strings.TrimSpace(item.English) if title == "" {
if title == "" { title = strings.TrimSpace(item.Title)
title = strings.TrimSpace(item.Title) }
} if title == "" {
if title == "" { return Entry{}, false
continue }
}
airType := AirType(strings.ToUpper(strings.TrimSpace(item.AirType)))
episodeNumber := item.EpisodeNumber if airType != AirTypeSUB {
subtracted := item.SubtractedEpisodeNumber return Entry{}, false
episodeText := "" }
switch {
case subtracted > 0 && subtracted < episodeNumber: episodeTime := item.EpisodeDate.In(location)
episodeText = fmt.Sprintf("Ep %d-%d", subtracted, episodeNumber)
case episodeNumber > 0: return Entry{
episodeText = fmt.Sprintf("Ep %d", episodeNumber) Title: title,
default: AnimeURL: joinURLPath("https://animeschedule.net/anime/", item.Route),
episodeText = "Ep ?" ImageURL: joinURLPath("https://img.animeschedule.net/production/assets/public/img/", item.ImageVersionRoute),
} EpisodeText: formatEpisodeText(item.EpisodeNumber, item.SubtractedEpisodeNumber),
AirType: airType,
airType := AirType(strings.ToUpper(strings.TrimSpace(item.AirType))) AirsAt: episodeTime,
if airType != AirTypeSUB { LocalTime: episodeTime.Format("15:04"),
continue Weekday: episodeTime.Weekday(),
} }, true
}
episodeTime := item.EpisodeDate.In(location)
weekday := episodeTime.Weekday() func formatEpisodeText(episodeNumber int, subtracted int) string {
localTime := episodeTime.Format("15:04") switch {
case subtracted > 0 && subtracted < episodeNumber:
imageURL := "" return fmt.Sprintf("Ep %d-%d", subtracted, episodeNumber)
if strings.TrimSpace(item.ImageVersionRoute) != "" { case episodeNumber > 0:
imageURL = "https://img.animeschedule.net/production/assets/public/img/" + strings.TrimLeft(strings.TrimSpace(item.ImageVersionRoute), "/") return fmt.Sprintf("Ep %d", episodeNumber)
} default:
return "Ep ?"
animeURL := "" }
if strings.TrimSpace(item.Route) != "" { }
animeURL = "https://animeschedule.net/anime/" + strings.TrimLeft(strings.TrimSpace(item.Route), "/")
} func joinURLPath(base string, path string) string {
trimmed := strings.TrimSpace(path)
out.Days[weekday] = append(out.Days[weekday], Entry{ if trimmed == "" {
Title: title, return ""
AnimeURL: animeURL, }
ImageURL: imageURL,
EpisodeText: episodeText, return base + strings.TrimLeft(trimmed, "/")
AirType: airType,
AirsAt: episodeTime,
LocalTime: localTime,
Weekday: weekday,
})
}
return out, nil
} }