Add interactive release search (M6)

Release listing and grab in the shared arr client, a full-screen release
list (sort, hide rejected, rejection reasons, confirmation before grabbing
rejected releases; Usenet only), and a season/episode picker for Sonarr.
Overlays are now a stack so dialogs can open above the release list.
Add a fake Newznab indexer to the dev setup.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-20 18:09:19 +02:00
co-authored by Claude Sonnet 5.5
parent 446cbdd6c5
commit f928427993
18 changed files with 1002 additions and 23 deletions
+33
View File
@@ -5,6 +5,7 @@ import (
"context"
"net/http"
"net/url"
"strconv"
"git.stinnesbeck.com/nils/arr-tui/internal/arr"
)
@@ -166,3 +167,35 @@ func (c *Client) SearchSeries(ctx context.Context, seriesID int) error {
func (c *Client) Queue(ctx context.Context) ([]arr.QueueItem, error) {
return c.QueueWith(ctx, url.Values{"includeSeries": {"true"}, "includeEpisode": {"true"}})
}
// 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"`
}
// Episodes lists all episodes of a library series.
func (c *Client) Episodes(ctx context.Context, seriesID int) ([]Episode, error) {
var episodes []Episode
err := c.Do(ctx, http.MethodGet, "episode", url.Values{"seriesId": {strconv.Itoa(seriesID)}}, nil, &episodes)
return episodes, err
}
// EpisodeReleases runs an interactive search for one episode.
func (c *Client) EpisodeReleases(ctx context.Context, episodeID int) ([]arr.Release, error) {
return c.Client.Releases(ctx, url.Values{"episodeId": {strconv.Itoa(episodeID)}})
}
// SeasonReleases runs an interactive search for a whole season (season packs and episodes).
func (c *Client) SeasonReleases(ctx context.Context, seriesID, season int) ([]arr.Release, error) {
return c.Client.Releases(ctx, url.Values{
"seriesId": {strconv.Itoa(seriesID)},
"seasonNumber": {strconv.Itoa(season)},
})
}