Add the calendar view (M10)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -7,6 +7,7 @@ import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"git.stinnesbeck.com/nils/arr-tui/internal/arr"
|
||||
)
|
||||
@@ -210,14 +211,17 @@ func (c *Client) Queue(ctx context.Context) ([]arr.QueueItem, error) {
|
||||
|
||||
// Episode is an episode of a library series.
|
||||
type Episode struct {
|
||||
ID int `json:"id"`
|
||||
SeriesID int `json:"seriesId"`
|
||||
SeasonNumber int `json:"seasonNumber"`
|
||||
EpisodeNumber int `json:"episodeNumber"`
|
||||
Title string `json:"title"`
|
||||
AirDate string `json:"airDate"`
|
||||
HasFile bool `json:"hasFile"`
|
||||
Monitored bool `json:"monitored"`
|
||||
ID int `json:"id"`
|
||||
SeriesID int `json:"seriesId"`
|
||||
SeasonNumber int `json:"seasonNumber"`
|
||||
EpisodeNumber int `json:"episodeNumber"`
|
||||
Title string `json:"title"`
|
||||
AirDate string `json:"airDate"`
|
||||
AirDateUTC string `json:"airDateUtc"`
|
||||
Overview string `json:"overview,omitempty"`
|
||||
HasFile bool `json:"hasFile"`
|
||||
Monitored bool `json:"monitored"`
|
||||
Series *Series `json:"series,omitempty"` // only with includeSeries
|
||||
}
|
||||
|
||||
// Episodes lists all episodes of a library series.
|
||||
@@ -257,3 +261,17 @@ func (c *Client) DeleteSeries(ctx context.Context, id int, deleteFiles, addExclu
|
||||
}
|
||||
return c.Do(ctx, http.MethodDelete, "series/"+strconv.Itoa(id), q, nil, nil)
|
||||
}
|
||||
|
||||
// Calendar lists the episodes airing between start and end, both inclusive,
|
||||
// with their series. Unmonitored episodes are only included when asked for.
|
||||
func (c *Client) Calendar(ctx context.Context, start, end time.Time, unmonitored bool) ([]Episode, error) {
|
||||
q := url.Values{
|
||||
"start": {start.Format("2006-01-02")},
|
||||
"end": {end.Format("2006-01-02")},
|
||||
"unmonitored": {strconv.FormatBool(unmonitored)},
|
||||
"includeSeries": {"true"},
|
||||
}
|
||||
var episodes []Episode
|
||||
err := c.Do(ctx, http.MethodGet, "calendar", q, nil, &episodes)
|
||||
return episodes, err
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
const lookupJSON = `[
|
||||
@@ -179,3 +180,21 @@ func TestDeleteSeries(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCalendar(t *testing.T) {
|
||||
c := newTestClient(t, func(w http.ResponseWriter, r *http.Request) {
|
||||
q := r.URL.Query()
|
||||
if r.URL.Path != "/api/v3/calendar" || q.Get("includeSeries") != "true" || q.Get("unmonitored") != "false" || q.Get("start") != "2026-10-20" {
|
||||
t.Errorf("unexpected request %s", r.URL)
|
||||
}
|
||||
w.Write([]byte(`[{"id":9,"seriesId":2,"seasonNumber":2,"episodeNumber":5,"title":"Welcome","airDate":"2026-10-21","airDateUtc":"2026-10-22T01:00:00Z","overview":"Pilot.","monitored":true,"series":{"id":2,"title":"Andor","images":[{"coverType":"poster","url":"/p.jpg"}]}}]`))
|
||||
})
|
||||
start := time.Date(2026, 10, 20, 0, 0, 0, 0, time.UTC)
|
||||
eps, err := c.Calendar(context.Background(), start, start.AddDate(0, 0, 13), false)
|
||||
if err != nil || len(eps) != 1 {
|
||||
t.Fatalf("eps=%v err=%v", eps, err)
|
||||
}
|
||||
if e := eps[0]; e.Series == nil || e.Series.Title != "Andor" || e.AirDateUTC != "2026-10-22T01:00:00Z" || e.Overview != "Pilot." || len(e.Series.Images) != 1 {
|
||||
t.Errorf("episode not decoded: %+v", e)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user