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
}
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")
q := u.Query()
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)
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("Accept", "application/json")
@@ -408,13 +434,13 @@ func fetchWeekAPI(ctx context.Context, httpClient *http.Client, token string, ye
res, err := client.Do(req)
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() }()
if res.StatusCode != http.StatusOK {
body, _ := io.ReadAll(io.LimitReader(res.Body, netutil.Bytes512))
return WeekSchedule{}, &HTTPStatusError{
return nil, &HTTPStatusError{
StatusCode: res.StatusCode,
URL: u.String(),
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
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
resolvedWeek := week
if resolvedYear == 0 || resolvedWeek == 0 {
resolvedYear, resolvedWeek = time.Now().In(time.Local).ISOWeek()
}
out := WeekSchedule{
Year: resolvedYear,
Week: resolvedWeek,
Days: map[time.Weekday][]Entry{},
}
for _, item := range payload {
title := strings.TrimSpace(item.English)
if title == "" {
title = strings.TrimSpace(item.Title)
}
if title == "" {
continue
}
episodeNumber := item.EpisodeNumber
subtracted := item.SubtractedEpisodeNumber
episodeText := ""
switch {
case subtracted > 0 && subtracted < episodeNumber:
episodeText = fmt.Sprintf("Ep %d-%d", subtracted, episodeNumber)
case episodeNumber > 0:
episodeText = fmt.Sprintf("Ep %d", episodeNumber)
default:
episodeText = "Ep ?"
}
airType := AirType(strings.ToUpper(strings.TrimSpace(item.AirType)))
if airType != AirTypeSUB {
continue
}
episodeTime := item.EpisodeDate.In(location)
weekday := episodeTime.Weekday()
localTime := episodeTime.Format("15:04")
imageURL := ""
if strings.TrimSpace(item.ImageVersionRoute) != "" {
imageURL = "https://img.animeschedule.net/production/assets/public/img/" + strings.TrimLeft(strings.TrimSpace(item.ImageVersionRoute), "/")
}
animeURL := ""
if strings.TrimSpace(item.Route) != "" {
animeURL = "https://animeschedule.net/anime/" + strings.TrimLeft(strings.TrimSpace(item.Route), "/")
}
out.Days[weekday] = append(out.Days[weekday], Entry{
Title: title,
AnimeURL: animeURL,
ImageURL: imageURL,
EpisodeText: episodeText,
AirType: airType,
AirsAt: episodeTime,
LocalTime: localTime,
Weekday: weekday,
})
}
return out, nil
return payload, nil
}
func resolveRequestedISOWeek(year int, week int) (int, int) {
if year > 0 && week > 0 {
return year, week
}
return time.Now().In(time.Local).ISOWeek()
}
func weekEntryFromAPI(item timetableAnimeAPI, location *time.Location) (Entry, bool) {
title := strings.TrimSpace(item.English)
if title == "" {
title = strings.TrimSpace(item.Title)
}
if title == "" {
return Entry{}, false
}
airType := AirType(strings.ToUpper(strings.TrimSpace(item.AirType)))
if airType != AirTypeSUB {
return Entry{}, false
}
episodeTime := item.EpisodeDate.In(location)
return Entry{
Title: title,
AnimeURL: joinURLPath("https://animeschedule.net/anime/", item.Route),
ImageURL: joinURLPath("https://img.animeschedule.net/production/assets/public/img/", item.ImageVersionRoute),
EpisodeText: formatEpisodeText(item.EpisodeNumber, item.SubtractedEpisodeNumber),
AirType: airType,
AirsAt: episodeTime,
LocalTime: episodeTime.Format("15:04"),
Weekday: episodeTime.Weekday(),
}, true
}
func formatEpisodeText(episodeNumber int, subtracted int) string {
switch {
case subtracted > 0 && subtracted < episodeNumber:
return fmt.Sprintf("Ep %d-%d", subtracted, episodeNumber)
case episodeNumber > 0:
return fmt.Sprintf("Ep %d", episodeNumber)
default:
return "Ep ?"
}
}
func joinURLPath(base string, path string) string {
trimmed := strings.TrimSpace(path)
if trimmed == "" {
return ""
}
return base + strings.TrimLeft(trimmed, "/")
}