From 52c55ce8f0fa29c209725f3c0f35bc48a9ab9e25 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Sun, 12 Apr 2026 23:55:32 -0700 Subject: [PATCH] Add all the methods. --- README.md | 16 +- lidarr/album.go | 75 + lidarr/artist.go | 92 + lidarr/autotagging.go | 130 + lidarr/customfilter.go | 110 + lidarr/delayprofile.go | 141 + lidarr/diskspace.go | 31 + lidarr/health.go | 31 + lidarr/metadataprofile.go | 81 + lidarr/parse.go | 53 + lidarr/qualityprofile.go | 17 + lidarr/system.go | 154 + lidarr/tag.go | 48 + lidarr/update.go | 34 + lidarr/wanted.go | 69 + prowlarr/app.go | 174 + prowlarr/appprofile.go | 133 + prowlarr/command.go | 119 + prowlarr/customfilter.go | 110 + prowlarr/diskspace.go | 31 + prowlarr/health.go | 31 + prowlarr/history.go | 112 + prowlarr/indexer.go | 45 + prowlarr/indexerproxy.go | 185 + prowlarr/system.go | 154 + prowlarr/tag.go | 48 + prowlarr/update.go | 34 + radarr/alttitle.go | 58 + radarr/autotagging.go | 130 + radarr/blocklist.go | 21 + radarr/collection.go | 127 + radarr/credit.go | 72 + radarr/customfilter.go | 110 + radarr/delayprofile.go | 21 + radarr/diskspace.go | 31 + radarr/health.go | 31 + radarr/history.go | 55 + radarr/indexerflag.go | 34 + radarr/language.go | 51 + radarr/movie.go | 28 +- radarr/parse.go | 41 + radarr/qualityprofile.go | 17 + radarr/system.go | 154 + radarr/tag.go | 48 + radarr/update.go | 34 + radarr/wanted.go | 69 + readarr/author.go | 65 + readarr/autotagging.go | 130 + readarr/book.go | 30 + readarr/command.go | 22 + readarr/customfilter.go | 110 + readarr/delayprofile.go | 141 + readarr/diskspace.go | 31 + readarr/health.go | 31 + readarr/parse.go | 40 + readarr/qualitydefinition.go | 109 + readarr/qualityprofile.go | 17 + readarr/system.go | 154 + readarr/tag.go | 48 + readarr/update.go | 34 + readarr/wanted.go | 69 + shared.go | 2 +- sonarr/autotagging.go | 19 +- sonarr/customfilter.go | 8 +- sonarr/diskspace.go | 9 +- sonarr/health.go | 9 +- sonarr/system.go | 16 +- sonarr/update.go | 22 +- specs/prowlarr.v1.04.12.2026.json | 6356 +++++++++++++ specs/readarr.v1.04.12.2026.json | 13781 ++++++++++++++++++++++++++++ starrcmd/dispatcher_test.go | 157 + starrshared/autotagging.go | 23 + starrshared/customfilter.go | 11 + starrshared/diskspace.go | 10 + starrshared/doc.go | 2 + starrshared/health.go | 10 + starrshared/system.go | 20 + starrshared/update.go | 25 + 78 files changed, 24821 insertions(+), 80 deletions(-) create mode 100644 lidarr/autotagging.go create mode 100644 lidarr/customfilter.go create mode 100644 lidarr/delayprofile.go create mode 100644 lidarr/diskspace.go create mode 100644 lidarr/health.go create mode 100644 lidarr/parse.go create mode 100644 lidarr/update.go create mode 100644 lidarr/wanted.go create mode 100644 prowlarr/app.go create mode 100644 prowlarr/appprofile.go create mode 100644 prowlarr/command.go create mode 100644 prowlarr/customfilter.go create mode 100644 prowlarr/diskspace.go create mode 100644 prowlarr/health.go create mode 100644 prowlarr/history.go create mode 100644 prowlarr/indexerproxy.go create mode 100644 prowlarr/update.go create mode 100644 radarr/alttitle.go create mode 100644 radarr/autotagging.go create mode 100644 radarr/collection.go create mode 100644 radarr/credit.go create mode 100644 radarr/customfilter.go create mode 100644 radarr/diskspace.go create mode 100644 radarr/health.go create mode 100644 radarr/indexerflag.go create mode 100644 radarr/language.go create mode 100644 radarr/parse.go create mode 100644 radarr/update.go create mode 100644 radarr/wanted.go create mode 100644 readarr/autotagging.go create mode 100644 readarr/customfilter.go create mode 100644 readarr/delayprofile.go create mode 100644 readarr/diskspace.go create mode 100644 readarr/health.go create mode 100644 readarr/parse.go create mode 100644 readarr/qualitydefinition.go create mode 100644 readarr/update.go create mode 100644 readarr/wanted.go create mode 100644 specs/prowlarr.v1.04.12.2026.json create mode 100644 specs/readarr.v1.04.12.2026.json create mode 100644 starrcmd/dispatcher_test.go create mode 100644 starrshared/autotagging.go create mode 100644 starrshared/customfilter.go create mode 100644 starrshared/diskspace.go create mode 100644 starrshared/doc.go create mode 100644 starrshared/health.go create mode 100644 starrshared/system.go create mode 100644 starrshared/update.go diff --git a/README.md b/README.md index 24b10721..9ce7adba 100644 --- a/README.md +++ b/README.md @@ -9,11 +9,11 @@ **Go library to interact with APIs in all the Starr apps.** -- [Lidarr](https://lidarr.audio) ([over 80 methods](https://pkg.go.dev/golift.io/starr@main/lidarr)) -- [Prowlarr](https://prowlarr.com) ([over 20 methods](https://pkg.go.dev/golift.io/starr@main/prowlarr)) -- [Radarr](https://radarr.video) ([over 100 methods](https://pkg.go.dev/golift.io/starr@main/radarr)) -- [Readarr](https://readarr.com) ([over 70 methods](https://pkg.go.dev/golift.io/starr@main/readarr)) -- [Sonarr](https://sonarr.tv) ([over 120 methods](https://pkg.go.dev/golift.io/starr@main/sonarr)) +- [Lidarr](https://lidarr.audio) ([view Go ref](https://pkg.go.dev/golift.io/starr@main/lidarr)) +- [Prowlarr](https://prowlarr.com) ([view Go ref](https://pkg.go.dev/golift.io/starr@main/prowlarr)) +- [Radarr](https://radarr.video) ([view Go ref](https://pkg.go.dev/golift.io/starr@main/radarr)) +- [Readarr](https://readarr.com) ([view Go ref](https://pkg.go.dev/golift.io/starr@main/readarr)) +- [Sonarr](https://sonarr.tv) ([view Go ref](https://pkg.go.dev/golift.io/starr@main/sonarr)) ### Webhooks & Scripts @@ -25,9 +25,9 @@ ## One 🌟 To Rule Them All -This library is slowly updated as new methods are needed or requested. If you have -specific needs this library doesn't currently meet, but should or could, please -[let us know](https://github.com/golift/starr/issues/new)! +Pretty much all the API methods are available. Plus Connections: Webhooks and Custom Scripts. +If you have specific needs this library doesn't currently meet, +but should or could, please [let us know](https://github.com/golift/starr/issues/new)! This library is currently in use by: diff --git a/lidarr/album.go b/lidarr/album.go index 3995832e..68bb3073 100644 --- a/lidarr/album.go +++ b/lidarr/album.go @@ -241,3 +241,78 @@ func (l *Lidarr) DeleteAlbumContext(ctx context.Context, albumID int64, deleteFi return nil } + +const bpAlbumStudio = APIver + "/albumstudio" + +// AlbumsMonitoredInput is the body for PUT /album/monitor. +type AlbumsMonitoredInput struct { + AlbumIDs []int64 `json:"albumIds"` + Monitored bool `json:"monitored"` +} + +// MonitoringOptions configures album studio monitoring. +type MonitoringOptions struct { + Monitor string `json:"monitor,omitempty"` + AlbumsToMonitor []string `json:"albumsToMonitor,omitempty"` + Monitored bool `json:"monitored,omitempty"` +} + +// AlbumStudioArtist is one artist block for album studio. +type AlbumStudioArtist struct { + ID int64 `json:"id"` + Monitored bool `json:"monitored,omitempty"` + Albums []*Album `json:"albums,omitempty"` +} + +// AlbumStudioInput is the body for POST /albumstudio. +type AlbumStudioInput struct { + Artist []*AlbumStudioArtist `json:"artist,omitempty"` + MonitoringOptions *MonitoringOptions `json:"monitoringOptions,omitempty"` + MonitorNewItems string `json:"monitorNewItems,omitempty"` +} + +// MonitorAlbums sets monitored state for the given album IDs. +func (l *Lidarr) MonitorAlbums(albumIDs []int64, monitored bool) ([]*Album, error) { + return l.MonitorAlbumsContext(context.Background(), albumIDs, monitored) +} + +// MonitorAlbumsContext sets monitored state for the given album IDs. +func (l *Lidarr) MonitorAlbumsContext(ctx context.Context, albumIDs []int64, monitored bool) ([]*Album, error) { + in := AlbumsMonitoredInput{AlbumIDs: albumIDs, Monitored: monitored} + + var body bytes.Buffer + if err := json.NewEncoder(&body).Encode(&in); err != nil { + return nil, fmt.Errorf("json.Marshal(%s): %w", path.Join(bpAlbum, "monitor"), err) + } + + var output []*Album + + req := starr.Request{URI: path.Join(bpAlbum, "monitor"), Body: &body} + if err := l.PutInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Put(%s): %w", &req, err) + } + + return output, nil +} + +// AlbumStudio triggers album studio actions (monitoring) for artists/albums. +func (l *Lidarr) AlbumStudio(in *AlbumStudioInput) error { + return l.AlbumStudioContext(context.Background(), in) +} + +// AlbumStudioContext triggers album studio actions (monitoring) for artists/albums. +func (l *Lidarr) AlbumStudioContext(ctx context.Context, in *AlbumStudioInput) error { + var body bytes.Buffer + if err := json.NewEncoder(&body).Encode(in); err != nil { + return fmt.Errorf("json.Marshal(%s): %w", bpAlbumStudio, err) + } + + var output any + + req := starr.Request{URI: bpAlbumStudio, Body: &body} + if err := l.PostInto(ctx, req, &output); err != nil { + return fmt.Errorf("api.Post(%s): %w", &req, err) + } + + return nil +} diff --git a/lidarr/artist.go b/lidarr/artist.go index 52ed28e9..1edb2d8b 100644 --- a/lidarr/artist.go +++ b/lidarr/artist.go @@ -14,6 +14,21 @@ import ( const bpArtist = APIver + "/artist" +// ArtistEditorInput is the request body for PUT and DELETE /artist/editor. +type ArtistEditorInput struct { + ArtistIDs []int `json:"artistIds,omitempty"` + Monitored *bool `json:"monitored,omitempty"` + MonitorNewItems string `json:"monitorNewItems,omitempty"` + QualityProfileID *int `json:"qualityProfileId,omitempty"` + MetadataProfileID *int `json:"metadataProfileId,omitempty"` + RootFolderPath string `json:"rootFolderPath,omitempty"` + Tags []int `json:"tags,omitempty"` + ApplyTags starr.ApplyTags `json:"applyTags,omitempty"` + MoveFiles bool `json:"moveFiles,omitempty"` + DeleteFiles bool `json:"deleteFiles,omitempty"` + AddImportListExclusion bool `json:"addImportListExclusion,omitempty"` +} + // Artist represents the /api/v1/artist endpoint, and it's part of an Album. type Artist struct { ID int64 `json:"id"` @@ -159,3 +174,80 @@ func (l *Lidarr) DeleteArtistContext(ctx context.Context, artistID int64, delete return nil } + +// LookupArtist searches for artists matching the specified search term. +func (l *Lidarr) LookupArtist(term string) ([]*Artist, error) { + return l.LookupArtistContext(context.Background(), term) +} + +// LookupArtistContext searches for artists matching the specified search term. +func (l *Lidarr) LookupArtistContext(ctx context.Context, term string) ([]*Artist, error) { + var output []*Artist + + if term == "" { + return output, nil + } + + req := starr.Request{ + URI: path.Join(bpArtist, "lookup"), + Query: make(url.Values), + } + req.Query.Set("term", term) + + if err := l.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return output, nil +} + +// EditArtists applies bulk edits to artists. +func (l *Lidarr) EditArtists(in *ArtistEditorInput) ([]*Artist, error) { + return l.EditArtistsContext(context.Background(), in) +} + +// EditArtistsContext applies bulk edits to artists. +func (l *Lidarr) EditArtistsContext(ctx context.Context, in *ArtistEditorInput) ([]*Artist, error) { + var body bytes.Buffer + if err := json.NewEncoder(&body).Encode(in); err != nil { + return nil, fmt.Errorf("json.Marshal(%s): %w", path.Join(bpArtist, "editor"), err) + } + + var output []*Artist + + req := starr.Request{URI: path.Join(bpArtist, "editor"), Body: &body} + if err := l.PutInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Put(%s): %w", &req, err) + } + + return output, nil +} + +// DeleteArtists applies bulk deletes to artists. +func (l *Lidarr) DeleteArtists(in *ArtistEditorInput) ([]*Artist, error) { + return l.DeleteArtistsContext(context.Background(), in) +} + +// DeleteArtistsContext applies bulk deletes to artists. +func (l *Lidarr) DeleteArtistsContext(ctx context.Context, in *ArtistEditorInput) ([]*Artist, error) { + var body bytes.Buffer + if err := json.NewEncoder(&body).Encode(in); err != nil { + return nil, fmt.Errorf("json.Marshal(%s): %w", path.Join(bpArtist, "editor"), err) + } + + req := starr.Request{URI: starr.SetAPIPath(path.Join(bpArtist, "editor")), Body: &body} + + resp, err := l.Delete(ctx, req) + if err != nil { + return nil, fmt.Errorf("api.Delete(%s): %w", &req, err) + } + defer resp.Body.Close() + + var output []*Artist + + if err := json.NewDecoder(resp.Body).Decode(&output); err != nil { + return nil, fmt.Errorf("decoding response from %s: %w", &req, err) + } + + return output, nil +} diff --git a/lidarr/autotagging.go b/lidarr/autotagging.go new file mode 100644 index 00000000..2d1a22f5 --- /dev/null +++ b/lidarr/autotagging.go @@ -0,0 +1,130 @@ +package lidarr + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "path" + + "golift.io/starr" + "golift.io/starr/starrshared" +) + +const bpAutoTagging = APIver + "/autotagging" + +// AutoTagging is the /api/v1/autotagging resource. +type AutoTagging = starrshared.AutoTagging + +// AutoTaggingSpecification is one rule inside an AutoTagging definition. +type AutoTaggingSpecification = starrshared.AutoTaggingSpecification + +// GetAutoTaggings returns all auto tagging configurations. +func (l *Lidarr) GetAutoTaggings() ([]*AutoTagging, error) { + return l.GetAutoTaggingsContext(context.Background()) +} + +// GetAutoTaggingsContext returns all auto tagging configurations. +func (l *Lidarr) GetAutoTaggingsContext(ctx context.Context) ([]*AutoTagging, error) { + var output []*AutoTagging + + req := starr.Request{URI: bpAutoTagging} + if err := l.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return output, nil +} + +// GetAutoTagging returns a single auto tagging configuration. +func (l *Lidarr) GetAutoTagging(id int) (*AutoTagging, error) { + return l.GetAutoTaggingContext(context.Background(), id) +} + +// GetAutoTaggingContext returns a single auto tagging configuration. +func (l *Lidarr) GetAutoTaggingContext(ctx context.Context, id int) (*AutoTagging, error) { + var output AutoTagging + + req := starr.Request{URI: path.Join(bpAutoTagging, starr.Str(id))} + if err := l.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return &output, nil +} + +// GetAutoTaggingSchema returns the specification schema templates for auto tagging. +func (l *Lidarr) GetAutoTaggingSchema() ([]*AutoTaggingSpecification, error) { + return l.GetAutoTaggingSchemaContext(context.Background()) +} + +// GetAutoTaggingSchemaContext returns the specification schema templates for auto tagging. +func (l *Lidarr) GetAutoTaggingSchemaContext(ctx context.Context) ([]*AutoTaggingSpecification, error) { + var output []*AutoTaggingSpecification + + req := starr.Request{URI: path.Join(bpAutoTagging, "schema")} + if err := l.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return output, nil +} + +// AddAutoTagging creates an auto tagging configuration. +func (l *Lidarr) AddAutoTagging(in *AutoTagging) (*AutoTagging, error) { + return l.AddAutoTaggingContext(context.Background(), in) +} + +// AddAutoTaggingContext creates an auto tagging configuration. +func (l *Lidarr) AddAutoTaggingContext(ctx context.Context, in *AutoTagging) (*AutoTagging, error) { + var output AutoTagging + + var body bytes.Buffer + if err := json.NewEncoder(&body).Encode(in); err != nil { + return nil, fmt.Errorf("json.Marshal(%s): %w", bpAutoTagging, err) + } + + req := starr.Request{URI: bpAutoTagging, Body: &body} + if err := l.PostInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Post(%s): %w", &req, err) + } + + return &output, nil +} + +// UpdateAutoTagging updates an auto tagging configuration. +func (l *Lidarr) UpdateAutoTagging(in *AutoTagging) (*AutoTagging, error) { + return l.UpdateAutoTaggingContext(context.Background(), in) +} + +// UpdateAutoTaggingContext updates an auto tagging configuration. +func (l *Lidarr) UpdateAutoTaggingContext(ctx context.Context, input *AutoTagging) (*AutoTagging, error) { + var output AutoTagging + + var body bytes.Buffer + if err := json.NewEncoder(&body).Encode(input); err != nil { + return nil, fmt.Errorf("json.Marshal(%s): %w", bpAutoTagging, err) + } + + req := starr.Request{URI: path.Join(bpAutoTagging, starr.Str(input.ID)), Body: &body} + if err := l.PutInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Put(%s): %w", &req, err) + } + + return &output, nil +} + +// DeleteAutoTagging deletes an auto tagging configuration. +func (l *Lidarr) DeleteAutoTagging(id int) error { + return l.DeleteAutoTaggingContext(context.Background(), id) +} + +// DeleteAutoTaggingContext deletes an auto tagging configuration. +func (l *Lidarr) DeleteAutoTaggingContext(ctx context.Context, id int) error { + req := starr.Request{URI: path.Join(bpAutoTagging, starr.Str(id))} + if err := l.DeleteAny(ctx, req); err != nil { + return fmt.Errorf("api.Delete(%s): %w", &req, err) + } + + return nil +} diff --git a/lidarr/customfilter.go b/lidarr/customfilter.go new file mode 100644 index 00000000..a6f84395 --- /dev/null +++ b/lidarr/customfilter.go @@ -0,0 +1,110 @@ +package lidarr + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "path" + + "golift.io/starr" + "golift.io/starr/starrshared" +) + +const bpCustomFilter = APIver + "/customfilter" + +// CustomFilter is the /api/v1/customfilter resource. +type CustomFilter = starrshared.CustomFilter + +// GetCustomFilters returns all custom filters. +func (l *Lidarr) GetCustomFilters() ([]*CustomFilter, error) { + return l.GetCustomFiltersContext(context.Background()) +} + +// GetCustomFiltersContext returns all custom filters. +func (l *Lidarr) GetCustomFiltersContext(ctx context.Context) ([]*CustomFilter, error) { + var output []*CustomFilter + + req := starr.Request{URI: bpCustomFilter} + if err := l.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return output, nil +} + +// GetCustomFilter returns a single custom filter. +func (l *Lidarr) GetCustomFilter(id int) (*CustomFilter, error) { + return l.GetCustomFilterContext(context.Background(), id) +} + +// GetCustomFilterContext returns a single custom filter. +func (l *Lidarr) GetCustomFilterContext(ctx context.Context, id int) (*CustomFilter, error) { + var output CustomFilter + + req := starr.Request{URI: path.Join(bpCustomFilter, starr.Str(id))} + if err := l.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return &output, nil +} + +// AddCustomFilter creates a custom filter. +func (l *Lidarr) AddCustomFilter(in *CustomFilter) (*CustomFilter, error) { + return l.AddCustomFilterContext(context.Background(), in) +} + +// AddCustomFilterContext creates a custom filter. +func (l *Lidarr) AddCustomFilterContext(ctx context.Context, in *CustomFilter) (*CustomFilter, error) { + var output CustomFilter + + var body bytes.Buffer + if err := json.NewEncoder(&body).Encode(in); err != nil { + return nil, fmt.Errorf("json.Marshal(%s): %w", bpCustomFilter, err) + } + + req := starr.Request{URI: bpCustomFilter, Body: &body} + if err := l.PostInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Post(%s): %w", &req, err) + } + + return &output, nil +} + +// UpdateCustomFilter updates a custom filter. +func (l *Lidarr) UpdateCustomFilter(in *CustomFilter) (*CustomFilter, error) { + return l.UpdateCustomFilterContext(context.Background(), in) +} + +// UpdateCustomFilterContext updates a custom filter. +func (l *Lidarr) UpdateCustomFilterContext(ctx context.Context, input *CustomFilter) (*CustomFilter, error) { + var output CustomFilter + + var body bytes.Buffer + if err := json.NewEncoder(&body).Encode(input); err != nil { + return nil, fmt.Errorf("json.Marshal(%s): %w", bpCustomFilter, err) + } + + req := starr.Request{URI: path.Join(bpCustomFilter, starr.Str(input.ID)), Body: &body} + if err := l.PutInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Put(%s): %w", &req, err) + } + + return &output, nil +} + +// DeleteCustomFilter deletes a custom filter. +func (l *Lidarr) DeleteCustomFilter(id int) error { + return l.DeleteCustomFilterContext(context.Background(), id) +} + +// DeleteCustomFilterContext deletes a custom filter. +func (l *Lidarr) DeleteCustomFilterContext(ctx context.Context, id int) error { + req := starr.Request{URI: path.Join(bpCustomFilter, starr.Str(id))} + if err := l.DeleteAny(ctx, req); err != nil { + return fmt.Errorf("api.Delete(%s): %w", &req, err) + } + + return nil +} diff --git a/lidarr/delayprofile.go b/lidarr/delayprofile.go new file mode 100644 index 00000000..2c95b045 --- /dev/null +++ b/lidarr/delayprofile.go @@ -0,0 +1,141 @@ +package lidarr + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "net/url" + "path" + + "golift.io/starr" +) + +// Define Base Path for Delay Profile calls. +const bpDelayProfile = APIver + "/delayProfile" + +// DelayProfile is the /api/v1/delayprofile endpoint. +type DelayProfile struct { + EnableUsenet bool `json:"enableUsenet,omitempty"` + EnableTorrent bool `json:"enableTorrent,omitempty"` + BypassIfHighestQuality bool `json:"bypassIfHighestQuality,omitempty"` + UsenetDelay int64 `json:"usenetDelay,omitempty"` + TorrentDelay int64 `json:"torrentDelay,omitempty"` + ID int64 `json:"id,omitempty"` + Order int64 `json:"order,omitempty"` + Tags []int `json:"tags"` + PreferredProtocol starr.Protocol `json:"preferredProtocol,omitempty"` +} + +// GetDelayProfiles returns all configured delay profiles. +func (l *Lidarr) GetDelayProfiles() ([]*DelayProfile, error) { + return l.GetDelayProfilesContext(context.Background()) +} + +// GetDelayProfilesContext returns all configured delay profiles. +func (l *Lidarr) GetDelayProfilesContext(ctx context.Context) ([]*DelayProfile, error) { + var output []*DelayProfile + + req := starr.Request{URI: bpDelayProfile} + if err := l.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return output, nil +} + +// GetDelayProfile returns a single delay profile. +func (l *Lidarr) GetDelayProfile(profileID int64) (*DelayProfile, error) { + return l.GetDelayProfileContext(context.Background(), profileID) +} + +// GetDelayProfileContext returns a single delay profile. +func (l *Lidarr) GetDelayProfileContext(ctx context.Context, profileID int64) (*DelayProfile, error) { + var output DelayProfile + + req := starr.Request{URI: path.Join(bpDelayProfile, starr.Str(profileID))} + if err := l.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return &output, nil +} + +// AddDelayProfile creates a delay profile. +func (l *Lidarr) AddDelayProfile(profile *DelayProfile) (*DelayProfile, error) { + return l.AddDelayProfileContext(context.Background(), profile) +} + +// AddDelayProfileContext creates a delay profile. +func (l *Lidarr) AddDelayProfileContext(ctx context.Context, profile *DelayProfile) (*DelayProfile, error) { + var output DelayProfile + + var body bytes.Buffer + if err := json.NewEncoder(&body).Encode(profile); err != nil { + return nil, fmt.Errorf("json.Marshal(%s): %w", bpDelayProfile, err) + } + + req := starr.Request{URI: bpDelayProfile, Body: &body} + if err := l.PostInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Post(%s): %w", &req, err) + } + + return &output, nil +} + +// UpdateDelayProfile updates the delay profile. +func (l *Lidarr) UpdateDelayProfile(profile *DelayProfile) (*DelayProfile, error) { + return l.UpdateDelayProfileContext(context.Background(), profile) +} + +// UpdateDelayProfileContext updates the delay profile. +func (l *Lidarr) UpdateDelayProfileContext(ctx context.Context, profile *DelayProfile) (*DelayProfile, error) { + var output DelayProfile + + var body bytes.Buffer + if err := json.NewEncoder(&body).Encode(profile); err != nil { + return nil, fmt.Errorf("json.Marshal(%s): %w", bpDelayProfile, err) + } + + req := starr.Request{URI: path.Join(bpDelayProfile, starr.Str(profile.ID)), Body: &body} + if err := l.PutInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Put(%s): %w", &req, err) + } + + return &output, nil +} + +// DeleteDelayProfile removes a single delay profile. +func (l *Lidarr) DeleteDelayProfile(profileID int64) error { + return l.DeleteDelayProfileContext(context.Background(), profileID) +} + +// DeleteDelayProfileContext removes a single delay profile. +func (l *Lidarr) DeleteDelayProfileContext(ctx context.Context, profileID int64) error { + req := starr.Request{URI: path.Join(bpDelayProfile, starr.Str(profileID))} + if err := l.DeleteAny(ctx, req); err != nil { + return fmt.Errorf("api.Delete(%s): %w", &req, err) + } + + return nil +} + +// ReorderDelayProfile moves a delay profile relative to another profile. +func (l *Lidarr) ReorderDelayProfile(id, afterID int64) ([]*DelayProfile, error) { + return l.ReorderDelayProfileContext(context.Background(), id, afterID) +} + +// ReorderDelayProfileContext moves a delay profile relative to another profile. +func (l *Lidarr) ReorderDelayProfileContext(ctx context.Context, id, afterID int64) ([]*DelayProfile, error) { + var output []*DelayProfile + + req := starr.Request{ + URI: path.Join(bpDelayProfile, "reorder", starr.Str(id)), + Query: url.Values{"after": []string{starr.Str(afterID)}}, + } + if err := l.PutInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Put(%s): %w", &req, err) + } + + return output, nil +} diff --git a/lidarr/diskspace.go b/lidarr/diskspace.go new file mode 100644 index 00000000..27c2d951 --- /dev/null +++ b/lidarr/diskspace.go @@ -0,0 +1,31 @@ +package lidarr + +import ( + "context" + "fmt" + + "golift.io/starr" + "golift.io/starr/starrshared" +) + +const bpDiskSpace = APIver + "/diskspace" + +// DiskSpace is the /api/v1/diskspace resource. +type DiskSpace = starrshared.DiskSpace + +// GetDiskSpace returns disk space information for Lidarr paths. +func (l *Lidarr) GetDiskSpace() ([]*DiskSpace, error) { + return l.GetDiskSpaceContext(context.Background()) +} + +// GetDiskSpaceContext returns disk space information for Lidarr paths. +func (l *Lidarr) GetDiskSpaceContext(ctx context.Context) ([]*DiskSpace, error) { + var output []*DiskSpace + + req := starr.Request{URI: bpDiskSpace} + if err := l.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return output, nil +} diff --git a/lidarr/health.go b/lidarr/health.go new file mode 100644 index 00000000..3e943f5a --- /dev/null +++ b/lidarr/health.go @@ -0,0 +1,31 @@ +package lidarr + +import ( + "context" + "fmt" + + "golift.io/starr" + "golift.io/starr/starrshared" +) + +const bpHealth = APIver + "/health" + +// Health is the /api/v1/health resource. +type Health = starrshared.Health + +// GetHealth returns current health check messages. +func (l *Lidarr) GetHealth() ([]*Health, error) { + return l.GetHealthContext(context.Background()) +} + +// GetHealthContext returns current health check messages. +func (l *Lidarr) GetHealthContext(ctx context.Context) ([]*Health, error) { + var output []*Health + + req := starr.Request{URI: bpHealth} + if err := l.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return output, nil +} diff --git a/lidarr/metadataprofile.go b/lidarr/metadataprofile.go index 83dbe007..c245143b 100644 --- a/lidarr/metadataprofile.go +++ b/lidarr/metadataprofile.go @@ -1,8 +1,11 @@ package lidarr import ( + "bytes" "context" + "encoding/json" "fmt" + "path" "golift.io/starr" ) @@ -46,3 +49,81 @@ func (l *Lidarr) GetMetadataProfilesContext(ctx context.Context) ([]*MetadataPro return output, nil } + +// GetMetadataProfile returns a single metadata profile. +func (l *Lidarr) GetMetadataProfile(profileID int64) (*MetadataProfile, error) { + return l.GetMetadataProfileContext(context.Background(), profileID) +} + +// GetMetadataProfileContext returns a single metadata profile. +func (l *Lidarr) GetMetadataProfileContext(ctx context.Context, profileID int64) (*MetadataProfile, error) { + var output MetadataProfile + + req := starr.Request{URI: path.Join(bpMetadataProfile, starr.Str(profileID))} + if err := l.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return &output, nil +} + +// AddMetadataProfile creates a metadata profile. +func (l *Lidarr) AddMetadataProfile(profile *MetadataProfile) (*MetadataProfile, error) { + return l.AddMetadataProfileContext(context.Background(), profile) +} + +// AddMetadataProfileContext creates a metadata profile. +func (l *Lidarr) AddMetadataProfileContext(ctx context.Context, profile *MetadataProfile) (*MetadataProfile, error) { + var output MetadataProfile + + profile.ID = 0 + + var body bytes.Buffer + if err := json.NewEncoder(&body).Encode(profile); err != nil { + return nil, fmt.Errorf("json.Marshal(%s): %w", bpMetadataProfile, err) + } + + req := starr.Request{URI: bpMetadataProfile, Body: &body} + if err := l.PostInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Post(%s): %w", &req, err) + } + + return &output, nil +} + +// UpdateMetadataProfile updates a metadata profile. +func (l *Lidarr) UpdateMetadataProfile(profile *MetadataProfile) (*MetadataProfile, error) { + return l.UpdateMetadataProfileContext(context.Background(), profile) +} + +// UpdateMetadataProfileContext updates a metadata profile. +func (l *Lidarr) UpdateMetadataProfileContext(ctx context.Context, profile *MetadataProfile) (*MetadataProfile, error) { + var output MetadataProfile + + var body bytes.Buffer + if err := json.NewEncoder(&body).Encode(profile); err != nil { + return nil, fmt.Errorf("json.Marshal(%s): %w", bpMetadataProfile, err) + } + + req := starr.Request{URI: path.Join(bpMetadataProfile, starr.Str(profile.ID)), Body: &body} + if err := l.PutInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Put(%s): %w", &req, err) + } + + return &output, nil +} + +// DeleteMetadataProfile deletes a metadata profile. +func (l *Lidarr) DeleteMetadataProfile(profileID int64) error { + return l.DeleteMetadataProfileContext(context.Background(), profileID) +} + +// DeleteMetadataProfileContext deletes a metadata profile. +func (l *Lidarr) DeleteMetadataProfileContext(ctx context.Context, profileID int64) error { + req := starr.Request{URI: path.Join(bpMetadataProfile, starr.Str(profileID))} + if err := l.DeleteAny(ctx, req); err != nil { + return fmt.Errorf("api.Delete(%s): %w", &req, err) + } + + return nil +} diff --git a/lidarr/parse.go b/lidarr/parse.go new file mode 100644 index 00000000..9fc42ad6 --- /dev/null +++ b/lidarr/parse.go @@ -0,0 +1,53 @@ +package lidarr + +import ( + "context" + "fmt" + "net/url" + + "golift.io/starr" +) + +const bpParse = APIver + "/parse" + +// ParsedAlbumInfo is returned when a release title parses as an album. +type ParsedAlbumInfo struct { + ReleaseTitle string `json:"releaseTitle,omitempty"` + AlbumTitle string `json:"albumTitle,omitempty"` + ArtistName string `json:"artistName,omitempty"` + AlbumType string `json:"albumType,omitempty"` + Quality *starr.Quality `json:"quality,omitempty"` + ReleaseDate string `json:"releaseDate,omitempty"` + Discography bool `json:"discography,omitempty"` + DiscographyStart int `json:"discographyStart,omitempty"` +} + +// ParseOutput is returned from GET /api/v1/parse. +type ParseOutput struct { + ID int64 `json:"id"` + Title string `json:"title,omitempty"` + ParsedAlbumInfo *ParsedAlbumInfo `json:"parsedAlbumInfo,omitempty"` + Artist *Artist `json:"artist,omitempty"` + Albums []*Album `json:"albums,omitempty"` + CustomFormats []*CustomFormatOutput `json:"customFormats,omitempty"` + CustomFormatScore int64 `json:"customFormatScore"` +} + +// Parse resolves a release title into parsed album metadata. +func (l *Lidarr) Parse(title string) (*ParseOutput, error) { + return l.ParseContext(context.Background(), title) +} + +// ParseContext resolves a release title into parsed album metadata. +func (l *Lidarr) ParseContext(ctx context.Context, title string) (*ParseOutput, error) { + var output *ParseOutput + + req := starr.Request{URI: bpParse, Query: make(url.Values)} + req.Query.Set("title", title) + + if err := l.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return output, nil +} diff --git a/lidarr/qualityprofile.go b/lidarr/qualityprofile.go index 831da505..28fbe766 100644 --- a/lidarr/qualityprofile.go +++ b/lidarr/qualityprofile.go @@ -42,6 +42,23 @@ func (l *Lidarr) GetQualityProfilesContext(ctx context.Context) ([]*QualityProfi return output, nil } +// GetQualityProfile returns a single quality profile. +func (l *Lidarr) GetQualityProfile(profileID int64) (*QualityProfile, error) { + return l.GetQualityProfileContext(context.Background(), profileID) +} + +// GetQualityProfileContext returns a single quality profile. +func (l *Lidarr) GetQualityProfileContext(ctx context.Context, profileID int64) (*QualityProfile, error) { + var output QualityProfile + + req := starr.Request{URI: path.Join(bpQualityProfile, starr.Str(profileID))} + if err := l.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return &output, nil +} + // AddQualityProfile updates a quality profile in place. func (l *Lidarr) AddQualityProfile(profile *QualityProfile) (int64, error) { return l.AddQualityProfileContext(context.Background(), profile) diff --git a/lidarr/system.go b/lidarr/system.go index a1d3290b..694212f2 100644 --- a/lidarr/system.go +++ b/lidarr/system.go @@ -1,12 +1,17 @@ package lidarr import ( + "bytes" "context" "fmt" + "io" + "mime/multipart" + "net/http" "path" "time" "golift.io/starr" + "golift.io/starr/starrshared" ) const bpSystem = APIver + "/system" @@ -78,3 +83,152 @@ func (l *Lidarr) GetBackupFilesContext(ctx context.Context) ([]*starr.BackupFile return output, nil } + +// SystemTask is a scheduled task from /api/v1/system/task. +type SystemTask = starrshared.SystemTask + +// BackupRestoreResponse is returned when restoring a backup. +type BackupRestoreResponse = starrshared.BackupRestoreResponse + +// DeleteBackup deletes a backup file by ID. +func (l *Lidarr) DeleteBackup(id int64) error { + return l.DeleteBackupContext(context.Background(), id) +} + +// DeleteBackupContext deletes a backup file by ID. +func (l *Lidarr) DeleteBackupContext(ctx context.Context, id int64) error { + req := starr.Request{URI: path.Join(bpSystem, "backup", starr.Str(id))} + if err := l.DeleteAny(ctx, req); err != nil { + return fmt.Errorf("api.Delete(%s): %w", &req, err) + } + + return nil +} + +// RestoreBackup restores an on-disk backup by ID. +func (l *Lidarr) RestoreBackup(id int64) (*BackupRestoreResponse, error) { + return l.RestoreBackupContext(context.Background(), id) +} + +// RestoreBackupContext restores an on-disk backup by ID. +func (l *Lidarr) RestoreBackupContext(ctx context.Context, id int64) (*BackupRestoreResponse, error) { + var output BackupRestoreResponse + + req := starr.Request{URI: path.Join(bpSystem, "backup", "restore", starr.Str(id))} + if err := l.PostInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Post(%s): %w", &req, err) + } + + return &output, nil +} + +// RestoreBackupUpload uploads a backup archive and restores it. +func (l *Lidarr) RestoreBackupUpload(filename string, file io.Reader) (*BackupRestoreResponse, error) { + return l.RestoreBackupUploadContext(context.Background(), filename, file) +} + +// RestoreBackupUploadContext uploads a backup archive and restores it. +func (l *Lidarr) RestoreBackupUploadContext( + ctx context.Context, filename string, file io.Reader, +) (*BackupRestoreResponse, error) { + var buf bytes.Buffer + + writer := multipart.NewWriter(&buf) + + part, err := writer.CreateFormFile("file", filename) + if err != nil { + return nil, fmt.Errorf("creating multipart form: %w", err) + } + + if _, err = io.Copy(part, file); err != nil { + return nil, fmt.Errorf("writing backup to multipart form: %w", err) + } + + if err = writer.Close(); err != nil { + return nil, fmt.Errorf("closing multipart writer: %w", err) + } + + var output BackupRestoreResponse + + hdr := make(http.Header) + hdr.Set("Content-Type", writer.FormDataContentType()) + + req := starr.Request{ + URI: path.Join(bpSystem, "backup", "restore", "upload"), + Body: &buf, + Headers: hdr, + } + if err := l.PostInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Post(%s): %w", &req, err) + } + + return &output, nil +} + +// Restart tells Lidarr to restart. +func (l *Lidarr) Restart() error { + return l.RestartContext(context.Background()) +} + +// RestartContext tells Lidarr to restart. +func (l *Lidarr) RestartContext(ctx context.Context) error { + var output any + + req := starr.Request{URI: path.Join(bpSystem, "restart")} + if err := l.PostInto(ctx, req, &output); err != nil { + return fmt.Errorf("api.Post(%s): %w", &req, err) + } + + return nil +} + +// Shutdown tells Lidarr to shut down. +func (l *Lidarr) Shutdown() error { + return l.ShutdownContext(context.Background()) +} + +// ShutdownContext tells Lidarr to shut down. +func (l *Lidarr) ShutdownContext(ctx context.Context) error { + var output any + + req := starr.Request{URI: path.Join(bpSystem, "shutdown")} + if err := l.PostInto(ctx, req, &output); err != nil { + return fmt.Errorf("api.Post(%s): %w", &req, err) + } + + return nil +} + +// GetSystemTasks returns all scheduled tasks. +func (l *Lidarr) GetSystemTasks() ([]*SystemTask, error) { + return l.GetSystemTasksContext(context.Background()) +} + +// GetSystemTasksContext returns all scheduled tasks. +func (l *Lidarr) GetSystemTasksContext(ctx context.Context) ([]*SystemTask, error) { + var output []*SystemTask + + req := starr.Request{URI: path.Join(bpSystem, "task")} + if err := l.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return output, nil +} + +// GetSystemTask returns a single scheduled task. +func (l *Lidarr) GetSystemTask(id int64) (*SystemTask, error) { + return l.GetSystemTaskContext(context.Background(), id) +} + +// GetSystemTaskContext returns a single scheduled task. +func (l *Lidarr) GetSystemTaskContext(ctx context.Context, id int64) (*SystemTask, error) { + var output SystemTask + + req := starr.Request{URI: path.Join(bpSystem, "task", starr.Str(id))} + if err := l.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return &output, nil +} diff --git a/lidarr/tag.go b/lidarr/tag.go index b603337c..81a98b2a 100644 --- a/lidarr/tag.go +++ b/lidarr/tag.go @@ -104,3 +104,51 @@ func (l *Lidarr) DeleteTagContext(ctx context.Context, tagID int) error { return nil } + +// TagDetails is the /api/v1/tag/detail resource. +type TagDetails struct { + ID int `json:"id"` + Label string `json:"label,omitempty"` + DelayProfileIDs []int `json:"delayProfileIds,omitempty"` + ImportListIDs []int `json:"importListIds,omitempty"` + NotificationIDs []int `json:"notificationIds,omitempty"` + IndexerIDs []int `json:"indexerIds,omitempty"` + DownloadClientIDs []int `json:"downloadClientIds,omitempty"` + AutoTagIDs []int `json:"autoTagIds,omitempty"` + ArtistIDs []int `json:"artistIds,omitempty"` + IndexerProxyIDs []int `json:"indexerProxyIds,omitempty"` +} + +// GetTagDetails returns tag usage details for all tags. +func (l *Lidarr) GetTagDetails() ([]*TagDetails, error) { + return l.GetTagDetailsContext(context.Background()) +} + +// GetTagDetailsContext returns tag usage details for all tags. +func (l *Lidarr) GetTagDetailsContext(ctx context.Context) ([]*TagDetails, error) { + var output []*TagDetails + + req := starr.Request{URI: path.Join(bpTag, "detail")} + if err := l.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return output, nil +} + +// GetTagDetail returns tag usage details for a single tag. +func (l *Lidarr) GetTagDetail(tagID int) (*TagDetails, error) { + return l.GetTagDetailContext(context.Background(), tagID) +} + +// GetTagDetailContext returns tag usage details for a single tag. +func (l *Lidarr) GetTagDetailContext(ctx context.Context, tagID int) (*TagDetails, error) { + var output TagDetails + + req := starr.Request{URI: path.Join(bpTag, "detail", starr.Str(tagID))} + if err := l.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return &output, nil +} diff --git a/lidarr/update.go b/lidarr/update.go new file mode 100644 index 00000000..4466e9a8 --- /dev/null +++ b/lidarr/update.go @@ -0,0 +1,34 @@ +package lidarr + +import ( + "context" + "fmt" + + "golift.io/starr" + "golift.io/starr/starrshared" +) + +const bpUpdate = APIver + "/update" + +// UpdateChanges is the change log embedded in Update. +type UpdateChanges = starrshared.UpdateChanges + +// Update is one available or installed update from /api/v1/update. +type Update = starrshared.Update + +// GetUpdates returns available application updates. +func (l *Lidarr) GetUpdates() ([]*Update, error) { + return l.GetUpdatesContext(context.Background()) +} + +// GetUpdatesContext returns available application updates. +func (l *Lidarr) GetUpdatesContext(ctx context.Context) ([]*Update, error) { + var output []*Update + + req := starr.Request{URI: bpUpdate} + if err := l.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return output, nil +} diff --git a/lidarr/wanted.go b/lidarr/wanted.go new file mode 100644 index 00000000..846f16a5 --- /dev/null +++ b/lidarr/wanted.go @@ -0,0 +1,69 @@ +package lidarr + +import ( + "context" + "fmt" + "path" + + "golift.io/starr" +) + +const bpWanted = APIver + "/wanted" + +// WantedAlbumsPage is a paged list of albums from /api/v1/wanted/missing or /wanted/cutoff. +type WantedAlbumsPage struct { + Page int `json:"page"` + PageSize int `json:"pageSize"` + SortKey string `json:"sortKey,omitempty"` + SortDirection string `json:"sortDirection,omitempty"` + TotalRecords int `json:"totalRecords"` + Records []*Album `json:"records"` +} + +func wantedPageParams(params *starr.PageReq) *starr.PageReq { + if params == nil { + return &starr.PageReq{} + } + + return params +} + +// GetWantedMissingPage returns a page of missing albums. +func (l *Lidarr) GetWantedMissingPage(params *starr.PageReq) (*WantedAlbumsPage, error) { + return l.GetWantedMissingPageContext(context.Background(), params) +} + +// GetWantedMissingPageContext returns a page of missing albums. +func (l *Lidarr) GetWantedMissingPageContext(ctx context.Context, params *starr.PageReq) (*WantedAlbumsPage, error) { + var output WantedAlbumsPage + + p := wantedPageParams(params) + p.CheckSet("sortKey", "releaseDate") + + req := starr.Request{URI: path.Join(bpWanted, "missing"), Query: p.Params()} + if err := l.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return &output, nil +} + +// GetWantedCutoffPage returns a page of albums past quality cutoff. +func (l *Lidarr) GetWantedCutoffPage(params *starr.PageReq) (*WantedAlbumsPage, error) { + return l.GetWantedCutoffPageContext(context.Background(), params) +} + +// GetWantedCutoffPageContext returns a page of albums past quality cutoff. +func (l *Lidarr) GetWantedCutoffPageContext(ctx context.Context, params *starr.PageReq) (*WantedAlbumsPage, error) { + var output WantedAlbumsPage + + p := wantedPageParams(params) + p.CheckSet("sortKey", "releaseDate") + + req := starr.Request{URI: path.Join(bpWanted, "cutoff"), Query: p.Params()} + if err := l.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return &output, nil +} diff --git a/prowlarr/app.go b/prowlarr/app.go new file mode 100644 index 00000000..8c139fe4 --- /dev/null +++ b/prowlarr/app.go @@ -0,0 +1,174 @@ +package prowlarr + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "net/url" + "path" + + "golift.io/starr" +) + +const bpApplication = APIver + "/applications" + +// ApplicationInput is used to create or update a connected application. +type ApplicationInput struct { + ID int64 `json:"id,omitempty"` + Name string `json:"name,omitempty"` + SyncLevel string `json:"syncLevel,omitempty"` + Implementation string `json:"implementation,omitempty"` + ConfigContract string `json:"configContract,omitempty"` + AppProfileID int64 `json:"appProfileId,omitempty"` + Tags []int `json:"tags,omitempty"` + Fields []*starr.FieldInput `json:"fields,omitempty"` +} + +// ApplicationOutput is returned from application endpoints. +type ApplicationOutput struct { + ID int64 `json:"id,omitempty"` + Name string `json:"name,omitempty"` + SyncLevel string `json:"syncLevel,omitempty"` + Implementation string `json:"implementation,omitempty"` + ImplementationName string `json:"implementationName,omitempty"` + ConfigContract string `json:"configContract,omitempty"` + AppProfileID int64 `json:"appProfileId,omitempty"` + Tags []int `json:"tags,omitempty"` + Fields []*starr.FieldOutput `json:"fields,omitempty"` +} + +// GetApplications returns all connected applications. +func (p *Prowlarr) GetApplications() ([]*ApplicationOutput, error) { + return p.GetApplicationsContext(context.Background()) +} + +// GetApplicationsContext returns all connected applications. +func (p *Prowlarr) GetApplicationsContext(ctx context.Context) ([]*ApplicationOutput, error) { + var output []*ApplicationOutput + + req := starr.Request{URI: bpApplication} + if err := p.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return output, nil +} + +// GetApplication returns a single application. +func (p *Prowlarr) GetApplication(id int64) (*ApplicationOutput, error) { + return p.GetApplicationContext(context.Background(), id) +} + +// GetApplicationContext returns a single application. +func (p *Prowlarr) GetApplicationContext(ctx context.Context, id int64) (*ApplicationOutput, error) { + var output ApplicationOutput + + req := starr.Request{URI: path.Join(bpApplication, starr.Str(id))} + if err := p.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return &output, nil +} + +// AddApplication creates a connected application. +func (p *Prowlarr) AddApplication(app *ApplicationInput, forceSave bool) (*ApplicationOutput, error) { + return p.AddApplicationContext(context.Background(), app, forceSave) +} + +// AddApplicationContext creates a connected application. +func (p *Prowlarr) AddApplicationContext( + ctx context.Context, + app *ApplicationInput, + forceSave bool, +) (*ApplicationOutput, error) { + var output ApplicationOutput + + var body bytes.Buffer + if err := json.NewEncoder(&body).Encode(app); err != nil { + return nil, fmt.Errorf("json.Marshal(%s): %w", bpApplication, err) + } + + req := starr.Request{ + URI: bpApplication, + Body: &body, + Query: url.Values{"forceSave": []string{starr.Str(forceSave)}}, + } + if err := p.PostInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Post(%s): %w", &req, err) + } + + return &output, nil +} + +// UpdateApplication updates a connected application. +func (p *Prowlarr) UpdateApplication(app *ApplicationInput, forceSave bool) (*ApplicationOutput, error) { + return p.UpdateApplicationContext(context.Background(), app, forceSave) +} + +// UpdateApplicationContext updates a connected application. +func (p *Prowlarr) UpdateApplicationContext( + ctx context.Context, + app *ApplicationInput, + forceSave bool, +) (*ApplicationOutput, error) { + var output ApplicationOutput + + var body bytes.Buffer + if err := json.NewEncoder(&body).Encode(app); err != nil { + return nil, fmt.Errorf("json.Marshal(%s): %w", bpApplication, err) + } + + req := starr.Request{ + URI: path.Join(bpApplication, starr.Str(app.ID)), + Body: &body, + Query: url.Values{"forceSave": []string{starr.Str(forceSave)}}, + } + if err := p.PutInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Put(%s): %w", &req, err) + } + + return &output, nil +} + +// DeleteApplication removes a connected application. +func (p *Prowlarr) DeleteApplication(id int64) error { + return p.DeleteApplicationContext(context.Background(), id) +} + +// DeleteApplicationContext removes a connected application. +func (p *Prowlarr) DeleteApplicationContext(ctx context.Context, id int64) error { + req := starr.Request{URI: path.Join(bpApplication, starr.Str(id))} + if err := p.DeleteAny(ctx, req); err != nil { + return fmt.Errorf("api.Delete(%s): %w", &req, err) + } + + return nil +} + +// TestApplication tests connection settings for an application definition. +func (p *Prowlarr) TestApplication(app *ApplicationInput, forceTest bool) error { + return p.TestApplicationContext(context.Background(), app, forceTest) +} + +// TestApplicationContext tests connection settings for an application definition. +func (p *Prowlarr) TestApplicationContext(ctx context.Context, app *ApplicationInput, forceTest bool) error { + var body bytes.Buffer + if err := json.NewEncoder(&body).Encode(app); err != nil { + return fmt.Errorf("json.Marshal(%s): %w", path.Join(bpApplication, "test"), err) + } + + var output any + + req := starr.Request{ + URI: path.Join(bpApplication, "test"), + Body: &body, + Query: url.Values{"forceTest": []string{starr.Str(forceTest)}}, + } + if err := p.PostInto(ctx, req, &output); err != nil { + return fmt.Errorf("api.Post(%s): %w", &req, err) + } + + return nil +} diff --git a/prowlarr/appprofile.go b/prowlarr/appprofile.go new file mode 100644 index 00000000..f1daac37 --- /dev/null +++ b/prowlarr/appprofile.go @@ -0,0 +1,133 @@ +package prowlarr + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "path" + + "golift.io/starr" +) + +const bpAppProfile = APIver + "/appprofile" + +// AppProfile is a Prowlarr application profile. +type AppProfile struct { + ID int64 `json:"id,omitempty"` + Name string `json:"name,omitempty"` + EnableRss bool `json:"enableRss"` + EnableAutomaticSearch bool `json:"enableAutomaticSearch"` + EnableInteractiveSearch bool `json:"enableInteractiveSearch"` + MinimumSeeders int `json:"minimumSeeders,omitempty"` +} + +// GetAppProfiles returns all application profiles. +func (p *Prowlarr) GetAppProfiles() ([]*AppProfile, error) { + return p.GetAppProfilesContext(context.Background()) +} + +// GetAppProfilesContext returns all application profiles. +func (p *Prowlarr) GetAppProfilesContext(ctx context.Context) ([]*AppProfile, error) { + var output []*AppProfile + + req := starr.Request{URI: bpAppProfile} + if err := p.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return output, nil +} + +// GetAppProfile returns a single application profile. +func (p *Prowlarr) GetAppProfile(id int64) (*AppProfile, error) { + return p.GetAppProfileContext(context.Background(), id) +} + +// GetAppProfileContext returns a single application profile. +func (p *Prowlarr) GetAppProfileContext(ctx context.Context, id int64) (*AppProfile, error) { + var output AppProfile + + req := starr.Request{URI: path.Join(bpAppProfile, starr.Str(id))} + if err := p.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return &output, nil +} + +// GetAppProfileSchema returns default application profile templates. +func (p *Prowlarr) GetAppProfileSchema() (*AppProfile, error) { + return p.GetAppProfileSchemaContext(context.Background()) +} + +// GetAppProfileSchemaContext returns default application profile templates. +func (p *Prowlarr) GetAppProfileSchemaContext(ctx context.Context) (*AppProfile, error) { + var output AppProfile + + req := starr.Request{URI: path.Join(bpAppProfile, "schema")} + if err := p.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return &output, nil +} + +// AddAppProfile creates an application profile. +func (p *Prowlarr) AddAppProfile(profile *AppProfile) (*AppProfile, error) { + return p.AddAppProfileContext(context.Background(), profile) +} + +// AddAppProfileContext creates an application profile. +func (p *Prowlarr) AddAppProfileContext(ctx context.Context, profile *AppProfile) (*AppProfile, error) { + var output AppProfile + + var body bytes.Buffer + if err := json.NewEncoder(&body).Encode(profile); err != nil { + return nil, fmt.Errorf("json.Marshal(%s): %w", bpAppProfile, err) + } + + req := starr.Request{URI: bpAppProfile, Body: &body} + if err := p.PostInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Post(%s): %w", &req, err) + } + + return &output, nil +} + +// UpdateAppProfile updates an application profile. +func (p *Prowlarr) UpdateAppProfile(profile *AppProfile) (*AppProfile, error) { + return p.UpdateAppProfileContext(context.Background(), profile) +} + +// UpdateAppProfileContext updates an application profile. +func (p *Prowlarr) UpdateAppProfileContext(ctx context.Context, profile *AppProfile) (*AppProfile, error) { + var output AppProfile + + var body bytes.Buffer + if err := json.NewEncoder(&body).Encode(profile); err != nil { + return nil, fmt.Errorf("json.Marshal(%s): %w", bpAppProfile, err) + } + + req := starr.Request{URI: path.Join(bpAppProfile, starr.Str(profile.ID)), Body: &body} + if err := p.PutInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Put(%s): %w", &req, err) + } + + return &output, nil +} + +// DeleteAppProfile removes an application profile. +func (p *Prowlarr) DeleteAppProfile(id int64) error { + return p.DeleteAppProfileContext(context.Background(), id) +} + +// DeleteAppProfileContext removes an application profile. +func (p *Prowlarr) DeleteAppProfileContext(ctx context.Context, id int64) error { + req := starr.Request{URI: path.Join(bpAppProfile, starr.Str(id))} + if err := p.DeleteAny(ctx, req); err != nil { + return fmt.Errorf("api.Delete(%s): %w", &req, err) + } + + return nil +} diff --git a/prowlarr/command.go b/prowlarr/command.go new file mode 100644 index 00000000..742ce5f0 --- /dev/null +++ b/prowlarr/command.go @@ -0,0 +1,119 @@ +package prowlarr + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "path" + "time" + + "golift.io/starr" +) + +const bpCommand = APIver + "/command" + +// CommandRequest is sent to POST /api/v1/command. +type CommandRequest struct { + Name string `json:"name"` + Body map[string]any `json:"body,omitempty"` +} + +// CommandResponse is returned from command endpoints. +type CommandResponse struct { + ID int64 `json:"id"` + Name string `json:"name"` + CommandName string `json:"commandName"` + Message string `json:"message,omitempty"` + Priority string `json:"priority"` + Status string `json:"status"` + Queued time.Time `json:"queued"` + Started time.Time `json:"started,omitzero"` + Ended time.Time `json:"ended,omitzero"` + StateChangeTime time.Time `json:"stateChangeTime,omitzero"` + LastExecutionTime time.Time `json:"lastExecutionTime,omitzero"` + Duration string `json:"duration,omitempty"` + Trigger string `json:"trigger"` + SendUpdatesToClient bool `json:"sendUpdatesToClient"` + UpdateScheduledTask bool `json:"updateScheduledTask"` + Body map[string]any `json:"body"` +} + +// GetCommands returns queued and recent commands. +func (p *Prowlarr) GetCommands() ([]*CommandResponse, error) { + return p.GetCommandsContext(context.Background()) +} + +// GetCommandsContext returns queued and recent commands. +func (p *Prowlarr) GetCommandsContext(ctx context.Context) ([]*CommandResponse, error) { + var output []*CommandResponse + + req := starr.Request{URI: bpCommand} + if err := p.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return output, nil +} + +// SendCommand queues a command. +func (p *Prowlarr) SendCommand(cmd *CommandRequest) (*CommandResponse, error) { + return p.SendCommandContext(context.Background(), cmd) +} + +// SendCommandContext queues a command. +func (p *Prowlarr) SendCommandContext(ctx context.Context, cmd *CommandRequest) (*CommandResponse, error) { + var output CommandResponse + + if cmd == nil || cmd.Name == "" { + return &output, nil + } + + var body bytes.Buffer + if err := json.NewEncoder(&body).Encode(cmd); err != nil { + return nil, fmt.Errorf("json.Marshal(%s): %w", bpCommand, err) + } + + req := starr.Request{URI: bpCommand, Body: &body} + if err := p.PostInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Post(%s): %w", &req, err) + } + + return &output, nil +} + +// GetCommandStatus returns a command by id. +func (p *Prowlarr) GetCommandStatus(commandID int64) (*CommandResponse, error) { + return p.GetCommandStatusContext(context.Background(), commandID) +} + +// GetCommandStatusContext returns a command by id. +func (p *Prowlarr) GetCommandStatusContext(ctx context.Context, commandID int64) (*CommandResponse, error) { + var output CommandResponse + + if commandID == 0 { + return &output, nil + } + + req := starr.Request{URI: path.Join(bpCommand, starr.Str(commandID))} + if err := p.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return &output, nil +} + +// DeleteCommand removes a queued command. +func (p *Prowlarr) DeleteCommand(commandID int64) error { + return p.DeleteCommandContext(context.Background(), commandID) +} + +// DeleteCommandContext removes a queued command. +func (p *Prowlarr) DeleteCommandContext(ctx context.Context, commandID int64) error { + req := starr.Request{URI: path.Join(bpCommand, starr.Str(commandID))} + if err := p.DeleteAny(ctx, req); err != nil { + return fmt.Errorf("api.Delete(%s): %w", &req, err) + } + + return nil +} diff --git a/prowlarr/customfilter.go b/prowlarr/customfilter.go new file mode 100644 index 00000000..01b5f3cc --- /dev/null +++ b/prowlarr/customfilter.go @@ -0,0 +1,110 @@ +package prowlarr + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "path" + + "golift.io/starr" + "golift.io/starr/starrshared" +) + +const bpCustomFilter = APIver + "/customfilter" + +// CustomFilter is the /api/v1/customfilter resource. +type CustomFilter = starrshared.CustomFilter + +// GetCustomFilters returns all custom filters. +func (p *Prowlarr) GetCustomFilters() ([]*CustomFilter, error) { + return p.GetCustomFiltersContext(context.Background()) +} + +// GetCustomFiltersContext returns all custom filters. +func (p *Prowlarr) GetCustomFiltersContext(ctx context.Context) ([]*CustomFilter, error) { + var output []*CustomFilter + + req := starr.Request{URI: bpCustomFilter} + if err := p.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return output, nil +} + +// GetCustomFilter returns a single custom filter. +func (p *Prowlarr) GetCustomFilter(id int) (*CustomFilter, error) { + return p.GetCustomFilterContext(context.Background(), id) +} + +// GetCustomFilterContext returns a single custom filter. +func (p *Prowlarr) GetCustomFilterContext(ctx context.Context, id int) (*CustomFilter, error) { + var output CustomFilter + + req := starr.Request{URI: path.Join(bpCustomFilter, starr.Str(id))} + if err := p.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return &output, nil +} + +// AddCustomFilter creates a custom filter. +func (p *Prowlarr) AddCustomFilter(in *CustomFilter) (*CustomFilter, error) { + return p.AddCustomFilterContext(context.Background(), in) +} + +// AddCustomFilterContext creates a custom filter. +func (p *Prowlarr) AddCustomFilterContext(ctx context.Context, in *CustomFilter) (*CustomFilter, error) { + var output CustomFilter + + var body bytes.Buffer + if err := json.NewEncoder(&body).Encode(in); err != nil { + return nil, fmt.Errorf("json.Marshal(%s): %w", bpCustomFilter, err) + } + + req := starr.Request{URI: bpCustomFilter, Body: &body} + if err := p.PostInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Post(%s): %w", &req, err) + } + + return &output, nil +} + +// UpdateCustomFilter updates a custom filter. +func (p *Prowlarr) UpdateCustomFilter(in *CustomFilter) (*CustomFilter, error) { + return p.UpdateCustomFilterContext(context.Background(), in) +} + +// UpdateCustomFilterContext updates a custom filter. +func (p *Prowlarr) UpdateCustomFilterContext(ctx context.Context, input *CustomFilter) (*CustomFilter, error) { + var output CustomFilter + + var body bytes.Buffer + if err := json.NewEncoder(&body).Encode(input); err != nil { + return nil, fmt.Errorf("json.Marshal(%s): %w", bpCustomFilter, err) + } + + req := starr.Request{URI: path.Join(bpCustomFilter, starr.Str(input.ID)), Body: &body} + if err := p.PutInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Put(%s): %w", &req, err) + } + + return &output, nil +} + +// DeleteCustomFilter deletes a custom filter. +func (p *Prowlarr) DeleteCustomFilter(id int) error { + return p.DeleteCustomFilterContext(context.Background(), id) +} + +// DeleteCustomFilterContext deletes a custom filter. +func (p *Prowlarr) DeleteCustomFilterContext(ctx context.Context, id int) error { + req := starr.Request{URI: path.Join(bpCustomFilter, starr.Str(id))} + if err := p.DeleteAny(ctx, req); err != nil { + return fmt.Errorf("api.Delete(%s): %w", &req, err) + } + + return nil +} diff --git a/prowlarr/diskspace.go b/prowlarr/diskspace.go new file mode 100644 index 00000000..aa7a5faa --- /dev/null +++ b/prowlarr/diskspace.go @@ -0,0 +1,31 @@ +package prowlarr + +import ( + "context" + "fmt" + + "golift.io/starr" + "golift.io/starr/starrshared" +) + +const bpDiskSpace = APIver + "/diskspace" + +// DiskSpace is the /api/v1/diskspace resource. +type DiskSpace = starrshared.DiskSpace + +// GetDiskSpace returns disk space information for Prowlarr paths. +func (p *Prowlarr) GetDiskSpace() ([]*DiskSpace, error) { + return p.GetDiskSpaceContext(context.Background()) +} + +// GetDiskSpaceContext returns disk space information for Prowlarr paths. +func (p *Prowlarr) GetDiskSpaceContext(ctx context.Context) ([]*DiskSpace, error) { + var output []*DiskSpace + + req := starr.Request{URI: bpDiskSpace} + if err := p.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return output, nil +} diff --git a/prowlarr/health.go b/prowlarr/health.go new file mode 100644 index 00000000..d37fa056 --- /dev/null +++ b/prowlarr/health.go @@ -0,0 +1,31 @@ +package prowlarr + +import ( + "context" + "fmt" + + "golift.io/starr" + "golift.io/starr/starrshared" +) + +const bpHealth = APIver + "/health" + +// Health is the /api/v1/health resource. +type Health = starrshared.Health + +// GetHealth returns current health check messages. +func (p *Prowlarr) GetHealth() ([]*Health, error) { + return p.GetHealthContext(context.Background()) +} + +// GetHealthContext returns current health check messages. +func (p *Prowlarr) GetHealthContext(ctx context.Context) ([]*Health, error) { + var output []*Health + + req := starr.Request{URI: bpHealth} + if err := p.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return output, nil +} diff --git a/prowlarr/history.go b/prowlarr/history.go new file mode 100644 index 00000000..5b58c44e --- /dev/null +++ b/prowlarr/history.go @@ -0,0 +1,112 @@ +package prowlarr + +import ( + "context" + "fmt" + "net/url" + "path" + "time" + + "golift.io/starr" +) + +const bpHistory = APIver + "/history" + +// HistoryPage is a paged history response. +type HistoryPage struct { + Page int `json:"page"` + PageSize int `json:"pageSize"` + SortKey string `json:"sortKey,omitempty"` + SortDirection string `json:"sortDirection,omitempty"` + TotalRecords int `json:"totalRecords"` + Records []*HistoryRecord `json:"records"` +} + +// HistoryRecord is one history entry. +type HistoryRecord struct { + ID int64 `json:"id"` + SourceTitle string `json:"sourceTitle,omitempty"` + Date time.Time `json:"date"` + EventType string `json:"eventType,omitempty"` + DownloadID string `json:"downloadId,omitempty"` + Data map[string]any `json:"data,omitempty"` +} + +// GetHistoryPage returns a page of history. +func (p *Prowlarr) GetHistoryPage(params *starr.PageReq) (*HistoryPage, error) { + return p.GetHistoryPageContext(context.Background(), params) +} + +// GetHistoryPageContext returns a page of history. +func (p *Prowlarr) GetHistoryPageContext(ctx context.Context, params *starr.PageReq) (*HistoryPage, error) { + if params == nil { + params = &starr.PageReq{} + } + + var output HistoryPage + + req := starr.Request{URI: bpHistory, Query: params.Params()} + if err := p.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return &output, nil +} + +// GetHistorySince returns history since a date. +func (p *Prowlarr) GetHistorySince(date time.Time, eventType string) ([]*HistoryRecord, error) { + return p.GetHistorySinceContext(context.Background(), date, eventType) +} + +// GetHistorySinceContext returns history since a date. +func (p *Prowlarr) GetHistorySinceContext( + ctx context.Context, + date time.Time, + eventType string, +) ([]*HistoryRecord, error) { + params := make(url.Values) + params.Set("date", date.UTC().Format(time.RFC3339)) + + if eventType != "" { + params.Set("eventType", eventType) + } + + var output []*HistoryRecord + + req := starr.Request{URI: path.Join(bpHistory, "since"), Query: params} + if err := p.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return output, nil +} + +// GetHistoryByIndexer returns history for an indexer. +func (p *Prowlarr) GetHistoryByIndexer(indexerID int64, eventType string, limit int) ([]*HistoryRecord, error) { + return p.GetHistoryByIndexerContext(context.Background(), indexerID, eventType, limit) +} + +// GetHistoryByIndexerContext returns history for an indexer. +func (p *Prowlarr) GetHistoryByIndexerContext( + ctx context.Context, indexerID int64, eventType string, limit int, +) ([]*HistoryRecord, error) { + params := make(url.Values) + params.Set("indexerId", starr.Str(indexerID)) + + if eventType != "" { + params.Set("eventType", eventType) + } + + if limit > 0 { + params.Set("limit", starr.Str(limit)) + } + + var output []*HistoryRecord + + req := starr.Request{URI: path.Join(bpHistory, "indexer"), Query: params} + if err := p.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return output, nil +} diff --git a/prowlarr/indexer.go b/prowlarr/indexer.go index 237cd685..f78131ec 100644 --- a/prowlarr/indexer.go +++ b/prowlarr/indexer.go @@ -79,6 +79,14 @@ type Categories struct { SubCategories []*Categories `json:"subCategories"` } +// IndexerDefaultCategory is a category from GetIndexerCategories (default category tree). +type IndexerDefaultCategory struct { + ID int64 `json:"id"` + Name string `json:"name,omitempty"` + Description string `json:"description,omitempty"` + SubCategories []*IndexerDefaultCategory `json:"subCategories,omitempty"` +} + // GetIndexers returns all configured indexers. func (p *Prowlarr) GetIndexers() ([]*IndexerOutput, error) { return p.GetIndexersContext(context.Background()) @@ -242,3 +250,40 @@ func (p *Prowlarr) UpdateIndexersContext(ctx context.Context, indexer *BulkIndex return &output, nil } + +// DeleteIndexers bulk-deletes indexers. +func (p *Prowlarr) DeleteIndexers(bulk *BulkIndexer) error { + return p.DeleteIndexersContext(context.Background(), bulk) +} + +// DeleteIndexersContext bulk-deletes indexers. +func (p *Prowlarr) DeleteIndexersContext(ctx context.Context, bulk *BulkIndexer) error { + var body bytes.Buffer + if err := json.NewEncoder(&body).Encode(bulk); err != nil { + return fmt.Errorf("json.Marshal(%s): %w", path.Join(bpIndexer, "bulk"), err) + } + + req := starr.Request{URI: path.Join(bpIndexer, "bulk"), Body: &body} + if err := p.DeleteAny(ctx, req); err != nil { + return fmt.Errorf("api.Delete(%s): %w", &req, err) + } + + return nil +} + +// GetIndexerCategories returns the default indexer category tree. +func (p *Prowlarr) GetIndexerCategories() ([]*IndexerDefaultCategory, error) { + return p.GetIndexerCategoriesContext(context.Background()) +} + +// GetIndexerCategoriesContext returns the default indexer category tree. +func (p *Prowlarr) GetIndexerCategoriesContext(ctx context.Context) ([]*IndexerDefaultCategory, error) { + var output []*IndexerDefaultCategory + + req := starr.Request{URI: path.Join(bpIndexer, "categories")} + if err := p.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return output, nil +} diff --git a/prowlarr/indexerproxy.go b/prowlarr/indexerproxy.go new file mode 100644 index 00000000..efb5d513 --- /dev/null +++ b/prowlarr/indexerproxy.go @@ -0,0 +1,185 @@ +package prowlarr + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "net/url" + "path" + + "golift.io/starr" +) + +const bpIndexerProxy = APIver + "/indexerproxy" + +// IndexerProxyInput is used to create or update an indexer proxy. +type IndexerProxyInput struct { + ID int64 `json:"id,omitempty"` + Name string `json:"name,omitempty"` + Implementation string `json:"implementation,omitempty"` + ConfigContract string `json:"configContract,omitempty"` + Fields []*starr.FieldInput `json:"fields,omitempty"` +} + +// IndexerProxyOutput is returned from indexer proxy endpoints. +type IndexerProxyOutput struct { + ID int64 `json:"id,omitempty"` + Name string `json:"name,omitempty"` + Implementation string `json:"implementation,omitempty"` + ImplementationName string `json:"implementationName,omitempty"` + ConfigContract string `json:"configContract,omitempty"` + Fields []*starr.FieldOutput `json:"fields,omitempty"` +} + +// GetIndexerProxies returns all indexer proxies. +func (p *Prowlarr) GetIndexerProxies() ([]*IndexerProxyOutput, error) { + return p.GetIndexerProxiesContext(context.Background()) +} + +// GetIndexerProxiesContext returns all indexer proxies. +func (p *Prowlarr) GetIndexerProxiesContext(ctx context.Context) ([]*IndexerProxyOutput, error) { + var output []*IndexerProxyOutput + + req := starr.Request{URI: bpIndexerProxy} + if err := p.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return output, nil +} + +// GetIndexerProxy returns a single indexer proxy. +func (p *Prowlarr) GetIndexerProxy(id int64) (*IndexerProxyOutput, error) { + return p.GetIndexerProxyContext(context.Background(), id) +} + +// GetIndexerProxyContext returns a single indexer proxy. +func (p *Prowlarr) GetIndexerProxyContext(ctx context.Context, id int64) (*IndexerProxyOutput, error) { + var output IndexerProxyOutput + + req := starr.Request{URI: path.Join(bpIndexerProxy, starr.Str(id))} + if err := p.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return &output, nil +} + +// GetIndexerProxySchema returns indexer proxy templates. +func (p *Prowlarr) GetIndexerProxySchema() ([]*IndexerProxyOutput, error) { + return p.GetIndexerProxySchemaContext(context.Background()) +} + +// GetIndexerProxySchemaContext returns indexer proxy templates. +func (p *Prowlarr) GetIndexerProxySchemaContext(ctx context.Context) ([]*IndexerProxyOutput, error) { + var output []*IndexerProxyOutput + + req := starr.Request{URI: path.Join(bpIndexerProxy, "schema")} + if err := p.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return output, nil +} + +// AddIndexerProxy creates an indexer proxy. +func (p *Prowlarr) AddIndexerProxy(proxy *IndexerProxyInput, forceSave bool) (*IndexerProxyOutput, error) { + return p.AddIndexerProxyContext(context.Background(), proxy, forceSave) +} + +// AddIndexerProxyContext creates an indexer proxy. +func (p *Prowlarr) AddIndexerProxyContext( + ctx context.Context, + proxy *IndexerProxyInput, + forceSave bool, +) (*IndexerProxyOutput, error) { + var output IndexerProxyOutput + + var body bytes.Buffer + if err := json.NewEncoder(&body).Encode(proxy); err != nil { + return nil, fmt.Errorf("json.Marshal(%s): %w", bpIndexerProxy, err) + } + + req := starr.Request{ + URI: bpIndexerProxy, + Body: &body, + Query: url.Values{"forceSave": []string{starr.Str(forceSave)}}, + } + if err := p.PostInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Post(%s): %w", &req, err) + } + + return &output, nil +} + +// UpdateIndexerProxy updates an indexer proxy. +func (p *Prowlarr) UpdateIndexerProxy(proxy *IndexerProxyInput, forceSave bool) (*IndexerProxyOutput, error) { + return p.UpdateIndexerProxyContext(context.Background(), proxy, forceSave) +} + +// UpdateIndexerProxyContext updates an indexer proxy. +func (p *Prowlarr) UpdateIndexerProxyContext( + ctx context.Context, + proxy *IndexerProxyInput, + forceSave bool, +) (*IndexerProxyOutput, error) { + var output IndexerProxyOutput + + var body bytes.Buffer + if err := json.NewEncoder(&body).Encode(proxy); err != nil { + return nil, fmt.Errorf("json.Marshal(%s): %w", bpIndexerProxy, err) + } + + req := starr.Request{ + URI: path.Join(bpIndexerProxy, starr.Str(proxy.ID)), + Body: &body, + Query: url.Values{"forceSave": []string{starr.Str(forceSave)}}, + } + if err := p.PutInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Put(%s): %w", &req, err) + } + + return &output, nil +} + +// DeleteIndexerProxy removes an indexer proxy. +func (p *Prowlarr) DeleteIndexerProxy(id int64) error { + return p.DeleteIndexerProxyContext(context.Background(), id) +} + +// DeleteIndexerProxyContext removes an indexer proxy. +func (p *Prowlarr) DeleteIndexerProxyContext(ctx context.Context, id int64) error { + req := starr.Request{URI: path.Join(bpIndexerProxy, starr.Str(id))} + if err := p.DeleteAny(ctx, req); err != nil { + return fmt.Errorf("api.Delete(%s): %w", &req, err) + } + + return nil +} + +// TestIndexerProxy tests indexer proxy settings. +func (p *Prowlarr) TestIndexerProxy(proxy *IndexerProxyInput, forceTest bool) error { + return p.TestIndexerProxyContext(context.Background(), proxy, forceTest) +} + +// TestIndexerProxyContext tests indexer proxy settings. +func (p *Prowlarr) TestIndexerProxyContext(ctx context.Context, proxy *IndexerProxyInput, forceTest bool) error { + var body bytes.Buffer + if err := json.NewEncoder(&body).Encode(proxy); err != nil { + return fmt.Errorf("json.Marshal(%s): %w", path.Join(bpIndexerProxy, "test"), err) + } + + var output any + + req := starr.Request{ + URI: path.Join(bpIndexerProxy, "test"), + Body: &body, + Query: url.Values{"forceTest": []string{starr.Str(forceTest)}}, + } + if err := p.PostInto(ctx, req, &output); err != nil { + return fmt.Errorf("api.Post(%s): %w", &req, err) + } + + return nil +} diff --git a/prowlarr/system.go b/prowlarr/system.go index 0a615655..5ef5546e 100644 --- a/prowlarr/system.go +++ b/prowlarr/system.go @@ -1,12 +1,17 @@ package prowlarr import ( + "bytes" "context" "fmt" + "io" + "mime/multipart" + "net/http" "path" "time" "golift.io/starr" + "golift.io/starr/starrshared" ) const bpSystem = APIver + "/system" @@ -81,3 +86,152 @@ func (p *Prowlarr) GetBackupFilesContext(ctx context.Context) ([]*starr.BackupFi return output, nil } + +// SystemTask is a scheduled task from /api/v1/system/task. +type SystemTask = starrshared.SystemTask + +// BackupRestoreResponse is returned when restoring a backup. +type BackupRestoreResponse = starrshared.BackupRestoreResponse + +// DeleteBackup deletes a backup file by ID. +func (p *Prowlarr) DeleteBackup(id int64) error { + return p.DeleteBackupContext(context.Background(), id) +} + +// DeleteBackupContext deletes a backup file by ID. +func (p *Prowlarr) DeleteBackupContext(ctx context.Context, id int64) error { + req := starr.Request{URI: path.Join(bpSystem, "backup", starr.Str(id))} + if err := p.DeleteAny(ctx, req); err != nil { + return fmt.Errorf("api.Delete(%s): %w", &req, err) + } + + return nil +} + +// RestoreBackup restores an on-disk backup by ID. +func (p *Prowlarr) RestoreBackup(id int64) (*BackupRestoreResponse, error) { + return p.RestoreBackupContext(context.Background(), id) +} + +// RestoreBackupContext restores an on-disk backup by ID. +func (p *Prowlarr) RestoreBackupContext(ctx context.Context, id int64) (*BackupRestoreResponse, error) { + var output BackupRestoreResponse + + req := starr.Request{URI: path.Join(bpSystem, "backup", "restore", starr.Str(id))} + if err := p.PostInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Post(%s): %w", &req, err) + } + + return &output, nil +} + +// RestoreBackupUpload uploads a backup archive and restores it. +func (p *Prowlarr) RestoreBackupUpload(filename string, file io.Reader) (*BackupRestoreResponse, error) { + return p.RestoreBackupUploadContext(context.Background(), filename, file) +} + +// RestoreBackupUploadContext uploads a backup archive and restores it. +func (p *Prowlarr) RestoreBackupUploadContext( + ctx context.Context, filename string, file io.Reader, +) (*BackupRestoreResponse, error) { + var buf bytes.Buffer + + writer := multipart.NewWriter(&buf) + + part, err := writer.CreateFormFile("file", filename) + if err != nil { + return nil, fmt.Errorf("creating multipart form: %w", err) + } + + if _, err = io.Copy(part, file); err != nil { + return nil, fmt.Errorf("writing backup to multipart form: %w", err) + } + + if err = writer.Close(); err != nil { + return nil, fmt.Errorf("closing multipart writer: %w", err) + } + + var output BackupRestoreResponse + + hdr := make(http.Header) + hdr.Set("Content-Type", writer.FormDataContentType()) + + req := starr.Request{ + URI: path.Join(bpSystem, "backup", "restore", "upload"), + Body: &buf, + Headers: hdr, + } + if err := p.PostInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Post(%s): %w", &req, err) + } + + return &output, nil +} + +// Restart tells Prowlarr to restart. +func (p *Prowlarr) Restart() error { + return p.RestartContext(context.Background()) +} + +// RestartContext tells Prowlarr to restart. +func (p *Prowlarr) RestartContext(ctx context.Context) error { + var output any + + req := starr.Request{URI: path.Join(bpSystem, "restart")} + if err := p.PostInto(ctx, req, &output); err != nil { + return fmt.Errorf("api.Post(%s): %w", &req, err) + } + + return nil +} + +// Shutdown tells Prowlarr to shut down. +func (p *Prowlarr) Shutdown() error { + return p.ShutdownContext(context.Background()) +} + +// ShutdownContext tells Prowlarr to shut down. +func (p *Prowlarr) ShutdownContext(ctx context.Context) error { + var output any + + req := starr.Request{URI: path.Join(bpSystem, "shutdown")} + if err := p.PostInto(ctx, req, &output); err != nil { + return fmt.Errorf("api.Post(%s): %w", &req, err) + } + + return nil +} + +// GetSystemTasks returns all scheduled tasks. +func (p *Prowlarr) GetSystemTasks() ([]*SystemTask, error) { + return p.GetSystemTasksContext(context.Background()) +} + +// GetSystemTasksContext returns all scheduled tasks. +func (p *Prowlarr) GetSystemTasksContext(ctx context.Context) ([]*SystemTask, error) { + var output []*SystemTask + + req := starr.Request{URI: path.Join(bpSystem, "task")} + if err := p.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return output, nil +} + +// GetSystemTask returns a single scheduled task. +func (p *Prowlarr) GetSystemTask(id int64) (*SystemTask, error) { + return p.GetSystemTaskContext(context.Background(), id) +} + +// GetSystemTaskContext returns a single scheduled task. +func (p *Prowlarr) GetSystemTaskContext(ctx context.Context, id int64) (*SystemTask, error) { + var output SystemTask + + req := starr.Request{URI: path.Join(bpSystem, "task", starr.Str(id))} + if err := p.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return &output, nil +} diff --git a/prowlarr/tag.go b/prowlarr/tag.go index 3e9694a5..abc8b52e 100644 --- a/prowlarr/tag.go +++ b/prowlarr/tag.go @@ -104,3 +104,51 @@ func (p *Prowlarr) DeleteTagContext(ctx context.Context, tagID int) error { return nil } + +// TagDetails is the /api/v1/tag/detail resource. +type TagDetails struct { + ID int `json:"id"` + Label string `json:"label,omitempty"` + DelayProfileIDs []int `json:"delayProfileIds,omitempty"` + ImportListIDs []int `json:"importListIds,omitempty"` + NotificationIDs []int `json:"notificationIds,omitempty"` + IndexerIDs []int `json:"indexerIds,omitempty"` + DownloadClientIDs []int `json:"downloadClientIds,omitempty"` + AutoTagIDs []int `json:"autoTagIds,omitempty"` + ApplicationIDs []int `json:"applicationIds,omitempty"` + IndexerProxyIDs []int `json:"indexerProxyIds,omitempty"` +} + +// GetTagDetails returns tag usage details for all tags. +func (p *Prowlarr) GetTagDetails() ([]*TagDetails, error) { + return p.GetTagDetailsContext(context.Background()) +} + +// GetTagDetailsContext returns tag usage details for all tags. +func (p *Prowlarr) GetTagDetailsContext(ctx context.Context) ([]*TagDetails, error) { + var output []*TagDetails + + req := starr.Request{URI: path.Join(bpTag, "detail")} + if err := p.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return output, nil +} + +// GetTagDetail returns tag usage details for a single tag. +func (p *Prowlarr) GetTagDetail(tagID int) (*TagDetails, error) { + return p.GetTagDetailContext(context.Background(), tagID) +} + +// GetTagDetailContext returns tag usage details for a single tag. +func (p *Prowlarr) GetTagDetailContext(ctx context.Context, tagID int) (*TagDetails, error) { + var output TagDetails + + req := starr.Request{URI: path.Join(bpTag, "detail", starr.Str(tagID))} + if err := p.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return &output, nil +} diff --git a/prowlarr/update.go b/prowlarr/update.go new file mode 100644 index 00000000..88f4ed9e --- /dev/null +++ b/prowlarr/update.go @@ -0,0 +1,34 @@ +package prowlarr + +import ( + "context" + "fmt" + + "golift.io/starr" + "golift.io/starr/starrshared" +) + +const bpUpdate = APIver + "/update" + +// UpdateChanges is the change log embedded in Update. +type UpdateChanges = starrshared.UpdateChanges + +// Update is one available or installed update from /api/v1/update. +type Update = starrshared.Update + +// GetUpdates returns available application updates. +func (p *Prowlarr) GetUpdates() ([]*Update, error) { + return p.GetUpdatesContext(context.Background()) +} + +// GetUpdatesContext returns available application updates. +func (p *Prowlarr) GetUpdatesContext(ctx context.Context) ([]*Update, error) { + var output []*Update + + req := starr.Request{URI: bpUpdate} + if err := p.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return output, nil +} diff --git a/radarr/alttitle.go b/radarr/alttitle.go new file mode 100644 index 00000000..a3506e95 --- /dev/null +++ b/radarr/alttitle.go @@ -0,0 +1,58 @@ +package radarr + +import ( + "context" + "fmt" + "net/url" + "path" + + "golift.io/starr" +) + +const bpAltTitle = APIver + "/alttitle" + +// GetAlternativeTitles returns alternative titles for a movie. +func (r *Radarr) GetAlternativeTitles(movieID, movieMetadataID int64) ([]*AlternativeTitle, error) { + return r.GetAlternativeTitlesContext(context.Background(), movieID, movieMetadataID) +} + +// GetAlternativeTitlesContext returns alternative titles for a movie. +func (r *Radarr) GetAlternativeTitlesContext( + ctx context.Context, + movieID, movieMetadataID int64, +) ([]*AlternativeTitle, error) { + params := make(url.Values) + if movieID != 0 { + params.Set("movieId", starr.Str(movieID)) + } + + if movieMetadataID != 0 { + params.Set("movieMetadataId", starr.Str(movieMetadataID)) + } + + var output []*AlternativeTitle + + req := starr.Request{URI: bpAltTitle, Query: params} + if err := r.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return output, nil +} + +// GetAlternativeTitle returns a single alternative title by id. +func (r *Radarr) GetAlternativeTitle(altTitleID int64) (*AlternativeTitle, error) { + return r.GetAlternativeTitleContext(context.Background(), altTitleID) +} + +// GetAlternativeTitleContext returns a single alternative title by id. +func (r *Radarr) GetAlternativeTitleContext(ctx context.Context, altTitleID int64) (*AlternativeTitle, error) { + var output AlternativeTitle + + req := starr.Request{URI: path.Join(bpAltTitle, starr.Str(altTitleID))} + if err := r.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return &output, nil +} diff --git a/radarr/autotagging.go b/radarr/autotagging.go new file mode 100644 index 00000000..93d4b1dd --- /dev/null +++ b/radarr/autotagging.go @@ -0,0 +1,130 @@ +package radarr + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "path" + + "golift.io/starr" + "golift.io/starr/starrshared" +) + +const bpAutoTagging = APIver + "/autotagging" + +// AutoTagging is the /api/v3/autotagging resource. +type AutoTagging = starrshared.AutoTagging + +// AutoTaggingSpecification is one rule inside an AutoTagging definition. +type AutoTaggingSpecification = starrshared.AutoTaggingSpecification + +// GetAutoTaggings returns all auto tagging configurations. +func (r *Radarr) GetAutoTaggings() ([]*AutoTagging, error) { + return r.GetAutoTaggingsContext(context.Background()) +} + +// GetAutoTaggingsContext returns all auto tagging configurations. +func (r *Radarr) GetAutoTaggingsContext(ctx context.Context) ([]*AutoTagging, error) { + var output []*AutoTagging + + req := starr.Request{URI: bpAutoTagging} + if err := r.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return output, nil +} + +// GetAutoTagging returns a single auto tagging configuration. +func (r *Radarr) GetAutoTagging(id int) (*AutoTagging, error) { + return r.GetAutoTaggingContext(context.Background(), id) +} + +// GetAutoTaggingContext returns a single auto tagging configuration. +func (r *Radarr) GetAutoTaggingContext(ctx context.Context, id int) (*AutoTagging, error) { + var output AutoTagging + + req := starr.Request{URI: path.Join(bpAutoTagging, starr.Str(id))} + if err := r.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return &output, nil +} + +// GetAutoTaggingSchema returns the specification schema templates for auto tagging. +func (r *Radarr) GetAutoTaggingSchema() ([]*AutoTaggingSpecification, error) { + return r.GetAutoTaggingSchemaContext(context.Background()) +} + +// GetAutoTaggingSchemaContext returns the specification schema templates for auto tagging. +func (r *Radarr) GetAutoTaggingSchemaContext(ctx context.Context) ([]*AutoTaggingSpecification, error) { + var output []*AutoTaggingSpecification + + req := starr.Request{URI: path.Join(bpAutoTagging, "schema")} + if err := r.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return output, nil +} + +// AddAutoTagging creates an auto tagging configuration. +func (r *Radarr) AddAutoTagging(in *AutoTagging) (*AutoTagging, error) { + return r.AddAutoTaggingContext(context.Background(), in) +} + +// AddAutoTaggingContext creates an auto tagging configuration. +func (r *Radarr) AddAutoTaggingContext(ctx context.Context, in *AutoTagging) (*AutoTagging, error) { + var output AutoTagging + + var body bytes.Buffer + if err := json.NewEncoder(&body).Encode(in); err != nil { + return nil, fmt.Errorf("json.Marshal(%s): %w", bpAutoTagging, err) + } + + req := starr.Request{URI: bpAutoTagging, Body: &body} + if err := r.PostInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Post(%s): %w", &req, err) + } + + return &output, nil +} + +// UpdateAutoTagging updates an auto tagging configuration. +func (r *Radarr) UpdateAutoTagging(in *AutoTagging) (*AutoTagging, error) { + return r.UpdateAutoTaggingContext(context.Background(), in) +} + +// UpdateAutoTaggingContext updates an auto tagging configuration. +func (r *Radarr) UpdateAutoTaggingContext(ctx context.Context, input *AutoTagging) (*AutoTagging, error) { + var output AutoTagging + + var body bytes.Buffer + if err := json.NewEncoder(&body).Encode(input); err != nil { + return nil, fmt.Errorf("json.Marshal(%s): %w", bpAutoTagging, err) + } + + req := starr.Request{URI: path.Join(bpAutoTagging, starr.Str(input.ID)), Body: &body} + if err := r.PutInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Put(%s): %w", &req, err) + } + + return &output, nil +} + +// DeleteAutoTagging deletes an auto tagging configuration. +func (r *Radarr) DeleteAutoTagging(id int) error { + return r.DeleteAutoTaggingContext(context.Background(), id) +} + +// DeleteAutoTaggingContext deletes an auto tagging configuration. +func (r *Radarr) DeleteAutoTaggingContext(ctx context.Context, id int) error { + req := starr.Request{URI: path.Join(bpAutoTagging, starr.Str(id))} + if err := r.DeleteAny(ctx, req); err != nil { + return fmt.Errorf("api.Delete(%s): %w", &req, err) + } + + return nil +} diff --git a/radarr/blocklist.go b/radarr/blocklist.go index 31199254..35db8418 100644 --- a/radarr/blocklist.go +++ b/radarr/blocklist.go @@ -5,6 +5,7 @@ import ( "context" "encoding/json" "fmt" + "net/url" "path" "time" @@ -131,3 +132,23 @@ func (r *Radarr) DeleteBlockListsContext(ctx context.Context, ids []int64) error return nil } + +// GetBlocklistByMovieID returns blocklist entries for a movie. +func (r *Radarr) GetBlocklistByMovieID(movieID int64) ([]*BlockListRecord, error) { + return r.GetBlocklistByMovieIDContext(context.Background(), movieID) +} + +// GetBlocklistByMovieIDContext returns blocklist entries for a movie. +func (r *Radarr) GetBlocklistByMovieIDContext(ctx context.Context, movieID int64) ([]*BlockListRecord, error) { + params := make(url.Values) + params.Set("movieId", starr.Str(movieID)) + + var output []*BlockListRecord + + req := starr.Request{URI: path.Join(bpBlocklist, "movie"), Query: params} + if err := r.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return output, nil +} diff --git a/radarr/collection.go b/radarr/collection.go new file mode 100644 index 00000000..eae07c87 --- /dev/null +++ b/radarr/collection.go @@ -0,0 +1,127 @@ +package radarr + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "net/url" + "path" + + "golift.io/starr" +) + +const bpCollection = APIver + "/collection" + +// Collection is the /api/v3/collection resource. +type Collection struct { + ID int `json:"id,omitempty"` + Title string `json:"title,omitempty"` + SortTitle string `json:"sortTitle,omitempty"` + TmdbID int64 `json:"tmdbId,omitempty"` + Images []*starr.Image `json:"images,omitempty"` + Overview string `json:"overview,omitempty"` + Monitored bool `json:"monitored"` + RootFolderPath string `json:"rootFolderPath,omitempty"` + QualityProfileID int64 `json:"qualityProfileId,omitempty"` + SearchOnAdd bool `json:"searchOnAdd"` + MinimumAvailability Availability `json:"minimumAvailability,omitempty"` + Movies []*Movie `json:"movies,omitempty"` + MissingMovies int `json:"missingMovies,omitempty"` + Tags []int `json:"tags,omitempty"` +} + +// CollectionUpdate is the body for PUT /collection (bulk update). +type CollectionUpdate struct { + CollectionIDs []int `json:"collectionIds"` + Monitored *bool `json:"monitored,omitempty"` + QualityProfileID *int `json:"qualityProfileId,omitempty"` + RootFolderPath string `json:"rootFolderPath,omitempty"` + SearchOnAdd *bool `json:"searchOnAdd,omitempty"` + MinimumAvailability Availability `json:"minimumAvailability,omitempty"` + Tags []int `json:"tags,omitempty"` + ApplyTags starr.ApplyTags `json:"applyTags,omitempty"` +} + +// GetCollections returns collections, optionally filtered by TMDb id. +func (r *Radarr) GetCollections(tmdbID int64) ([]*Collection, error) { + return r.GetCollectionsContext(context.Background(), tmdbID) +} + +// GetCollectionsContext returns collections, optionally filtered by TMDb id. +func (r *Radarr) GetCollectionsContext(ctx context.Context, tmdbID int64) ([]*Collection, error) { + params := make(url.Values) + if tmdbID != 0 { + params.Set("tmdbId", starr.Str(tmdbID)) + } + + var output []*Collection + + req := starr.Request{URI: bpCollection, Query: params} + if err := r.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return output, nil +} + +// GetCollection returns a single collection by database id. +func (r *Radarr) GetCollection(collectionID int64) (*Collection, error) { + return r.GetCollectionContext(context.Background(), collectionID) +} + +// GetCollectionContext returns a single collection by database id. +func (r *Radarr) GetCollectionContext(ctx context.Context, collectionID int64) (*Collection, error) { + var output Collection + + req := starr.Request{URI: path.Join(bpCollection, starr.Str(collectionID))} + if err := r.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return &output, nil +} + +// UpdateCollections applies a bulk update to collections. +func (r *Radarr) UpdateCollections(update *CollectionUpdate) ([]*Collection, error) { + return r.UpdateCollectionsContext(context.Background(), update) +} + +// UpdateCollectionsContext applies a bulk update to collections. +func (r *Radarr) UpdateCollectionsContext(ctx context.Context, update *CollectionUpdate) ([]*Collection, error) { + var body bytes.Buffer + if err := json.NewEncoder(&body).Encode(update); err != nil { + return nil, fmt.Errorf("json.Marshal(%s): %w", bpCollection, err) + } + + var output []*Collection + + req := starr.Request{URI: bpCollection, Body: &body} + if err := r.PutInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Put(%s): %w", &req, err) + } + + return output, nil +} + +// UpdateCollection updates a single collection. +func (r *Radarr) UpdateCollection(collection *Collection) (*Collection, error) { + return r.UpdateCollectionContext(context.Background(), collection) +} + +// UpdateCollectionContext updates a single collection. +func (r *Radarr) UpdateCollectionContext(ctx context.Context, collection *Collection) (*Collection, error) { + var body bytes.Buffer + if err := json.NewEncoder(&body).Encode(collection); err != nil { + return nil, fmt.Errorf("json.Marshal(%s): %w", bpCollection, err) + } + + var output Collection + + req := starr.Request{URI: path.Join(bpCollection, starr.Str(int64(collection.ID))), Body: &body} + if err := r.PutInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Put(%s): %w", &req, err) + } + + return &output, nil +} diff --git a/radarr/credit.go b/radarr/credit.go new file mode 100644 index 00000000..7f511842 --- /dev/null +++ b/radarr/credit.go @@ -0,0 +1,72 @@ +package radarr + +import ( + "context" + "fmt" + "net/url" + "path" + + "golift.io/starr" +) + +const bpCredit = APIver + "/credit" + +// Credit is a cast/crew credit from /api/v3/credit. +type Credit struct { + ID int64 `json:"id,omitempty"` + CreditID string `json:"creditId,omitempty"` + PersonName string `json:"personName,omitempty"` + Job string `json:"job,omitempty"` + Department string `json:"department,omitempty"` + Character string `json:"character,omitempty"` + Order int `json:"order,omitempty"` + ProfilePath string `json:"profilePath,omitempty"` + PersonTmdbID int64 `json:"personTmdbId,omitempty"` + MovieID int64 `json:"movieId,omitempty"` + MovieMetadataID int64 `json:"movieMetadataId,omitempty"` + Type string `json:"type,omitempty"` + Images []*starr.Image `json:"images,omitempty"` +} + +// GetCredits returns credits for a movie or movie metadata. +func (r *Radarr) GetCredits(movieID, movieMetadataID int64) ([]*Credit, error) { + return r.GetCreditsContext(context.Background(), movieID, movieMetadataID) +} + +// GetCreditsContext returns credits for a movie or movie metadata. +func (r *Radarr) GetCreditsContext(ctx context.Context, movieID, movieMetadataID int64) ([]*Credit, error) { + params := make(url.Values) + if movieID != 0 { + params.Set("movieId", starr.Str(movieID)) + } + + if movieMetadataID != 0 { + params.Set("movieMetadataId", starr.Str(movieMetadataID)) + } + + var output []*Credit + + req := starr.Request{URI: bpCredit, Query: params} + if err := r.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return output, nil +} + +// GetCredit returns a single credit by id. +func (r *Radarr) GetCredit(creditID int64) (*Credit, error) { + return r.GetCreditContext(context.Background(), creditID) +} + +// GetCreditContext returns a single credit by id. +func (r *Radarr) GetCreditContext(ctx context.Context, creditID int64) (*Credit, error) { + var output Credit + + req := starr.Request{URI: path.Join(bpCredit, starr.Str(creditID))} + if err := r.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return &output, nil +} diff --git a/radarr/customfilter.go b/radarr/customfilter.go new file mode 100644 index 00000000..81c03094 --- /dev/null +++ b/radarr/customfilter.go @@ -0,0 +1,110 @@ +package radarr + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "path" + + "golift.io/starr" + "golift.io/starr/starrshared" +) + +const bpCustomFilter = APIver + "/customfilter" + +// CustomFilter is the /api/v3/customfilter resource (UI saved filters, not custom formats). +type CustomFilter = starrshared.CustomFilter + +// GetCustomFilters returns all custom filters. +func (r *Radarr) GetCustomFilters() ([]*CustomFilter, error) { + return r.GetCustomFiltersContext(context.Background()) +} + +// GetCustomFiltersContext returns all custom filters. +func (r *Radarr) GetCustomFiltersContext(ctx context.Context) ([]*CustomFilter, error) { + var output []*CustomFilter + + req := starr.Request{URI: bpCustomFilter} + if err := r.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return output, nil +} + +// GetCustomFilter returns a single custom filter. +func (r *Radarr) GetCustomFilter(id int) (*CustomFilter, error) { + return r.GetCustomFilterContext(context.Background(), id) +} + +// GetCustomFilterContext returns a single custom filter. +func (r *Radarr) GetCustomFilterContext(ctx context.Context, id int) (*CustomFilter, error) { + var output CustomFilter + + req := starr.Request{URI: path.Join(bpCustomFilter, starr.Str(id))} + if err := r.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return &output, nil +} + +// AddCustomFilter creates a custom filter. +func (r *Radarr) AddCustomFilter(in *CustomFilter) (*CustomFilter, error) { + return r.AddCustomFilterContext(context.Background(), in) +} + +// AddCustomFilterContext creates a custom filter. +func (r *Radarr) AddCustomFilterContext(ctx context.Context, in *CustomFilter) (*CustomFilter, error) { + var output CustomFilter + + var body bytes.Buffer + if err := json.NewEncoder(&body).Encode(in); err != nil { + return nil, fmt.Errorf("json.Marshal(%s): %w", bpCustomFilter, err) + } + + req := starr.Request{URI: bpCustomFilter, Body: &body} + if err := r.PostInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Post(%s): %w", &req, err) + } + + return &output, nil +} + +// UpdateCustomFilter updates a custom filter. +func (r *Radarr) UpdateCustomFilter(in *CustomFilter) (*CustomFilter, error) { + return r.UpdateCustomFilterContext(context.Background(), in) +} + +// UpdateCustomFilterContext updates a custom filter. +func (r *Radarr) UpdateCustomFilterContext(ctx context.Context, input *CustomFilter) (*CustomFilter, error) { + var output CustomFilter + + var body bytes.Buffer + if err := json.NewEncoder(&body).Encode(input); err != nil { + return nil, fmt.Errorf("json.Marshal(%s): %w", bpCustomFilter, err) + } + + req := starr.Request{URI: path.Join(bpCustomFilter, starr.Str(input.ID)), Body: &body} + if err := r.PutInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Put(%s): %w", &req, err) + } + + return &output, nil +} + +// DeleteCustomFilter deletes a custom filter. +func (r *Radarr) DeleteCustomFilter(id int) error { + return r.DeleteCustomFilterContext(context.Background(), id) +} + +// DeleteCustomFilterContext deletes a custom filter. +func (r *Radarr) DeleteCustomFilterContext(ctx context.Context, id int) error { + req := starr.Request{URI: path.Join(bpCustomFilter, starr.Str(id))} + if err := r.DeleteAny(ctx, req); err != nil { + return fmt.Errorf("api.Delete(%s): %w", &req, err) + } + + return nil +} diff --git a/radarr/delayprofile.go b/radarr/delayprofile.go index d7e83bf2..1cf076e7 100644 --- a/radarr/delayprofile.go +++ b/radarr/delayprofile.go @@ -5,6 +5,7 @@ import ( "context" "encoding/json" "fmt" + "net/url" "path" "golift.io/starr" @@ -120,3 +121,23 @@ func (r *Radarr) DeleteDelayProfileContext(ctx context.Context, profileID int64) return nil } + +// ReorderDelayProfile moves a delay profile relative to another profile. +func (r *Radarr) ReorderDelayProfile(id, afterID int64) ([]*DelayProfile, error) { + return r.ReorderDelayProfileContext(context.Background(), id, afterID) +} + +// ReorderDelayProfileContext moves a delay profile relative to another profile. +func (r *Radarr) ReorderDelayProfileContext(ctx context.Context, id, afterID int64) ([]*DelayProfile, error) { + var output []*DelayProfile + + req := starr.Request{ + URI: path.Join(bpDelayProfile, "reorder", starr.Str(id)), + Query: url.Values{"after": []string{starr.Str(afterID)}}, + } + if err := r.PutInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Put(%s): %w", &req, err) + } + + return output, nil +} diff --git a/radarr/diskspace.go b/radarr/diskspace.go new file mode 100644 index 00000000..ad015f2d --- /dev/null +++ b/radarr/diskspace.go @@ -0,0 +1,31 @@ +package radarr + +import ( + "context" + "fmt" + + "golift.io/starr" + "golift.io/starr/starrshared" +) + +const bpDiskSpace = APIver + "/diskspace" + +// DiskSpace is the /api/v3/diskspace resource. +type DiskSpace = starrshared.DiskSpace + +// GetDiskSpace returns disk space information for Radarr paths. +func (r *Radarr) GetDiskSpace() ([]*DiskSpace, error) { + return r.GetDiskSpaceContext(context.Background()) +} + +// GetDiskSpaceContext returns disk space information for Radarr paths. +func (r *Radarr) GetDiskSpaceContext(ctx context.Context) ([]*DiskSpace, error) { + var output []*DiskSpace + + req := starr.Request{URI: bpDiskSpace} + if err := r.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return output, nil +} diff --git a/radarr/health.go b/radarr/health.go new file mode 100644 index 00000000..c45a8ff8 --- /dev/null +++ b/radarr/health.go @@ -0,0 +1,31 @@ +package radarr + +import ( + "context" + "fmt" + + "golift.io/starr" + "golift.io/starr/starrshared" +) + +const bpHealth = APIver + "/health" + +// Health is the /api/v3/health resource. +type Health = starrshared.Health + +// GetHealth returns current health check messages. +func (r *Radarr) GetHealth() ([]*Health, error) { + return r.GetHealthContext(context.Background()) +} + +// GetHealthContext returns current health check messages. +func (r *Radarr) GetHealthContext(ctx context.Context) ([]*Health, error) { + var output []*Health + + req := starr.Request{URI: bpHealth} + if err := r.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return output, nil +} diff --git a/radarr/history.go b/radarr/history.go index cc5bfaa3..ad1a6810 100644 --- a/radarr/history.go +++ b/radarr/history.go @@ -3,6 +3,7 @@ package radarr import ( "context" "fmt" + "net/url" "path" "time" @@ -118,6 +119,60 @@ func (r *Radarr) GetHistoryPageContext(ctx context.Context, params *starr.PageRe return &output, nil } +// GetHistoryByMovieID returns history records for a movie. +func (r *Radarr) GetHistoryByMovieID(movieID int64, eventType string, includeMovie bool) ([]*HistoryRecord, error) { + return r.GetHistoryByMovieIDContext(context.Background(), movieID, eventType, includeMovie) +} + +// GetHistoryByMovieIDContext returns history records for a movie. +func (r *Radarr) GetHistoryByMovieIDContext( + ctx context.Context, movieID int64, eventType string, includeMovie bool, +) ([]*HistoryRecord, error) { + params := make(url.Values) + params.Set("movieId", starr.Str(movieID)) + params.Set("includeMovie", starr.Str(includeMovie)) + + if eventType != "" { + params.Set("eventType", eventType) + } + + var output []*HistoryRecord + + req := starr.Request{URI: path.Join(bpHistory, "movie"), Query: params} + if err := r.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return output, nil +} + +// GetHistorySince returns history records since a date. +func (r *Radarr) GetHistorySince(date time.Time, eventType string, includeMovie bool) ([]*HistoryRecord, error) { + return r.GetHistorySinceContext(context.Background(), date, eventType, includeMovie) +} + +// GetHistorySinceContext returns history records since a date. +func (r *Radarr) GetHistorySinceContext( + ctx context.Context, date time.Time, eventType string, includeMovie bool, +) ([]*HistoryRecord, error) { + params := make(url.Values) + params.Set("date", date.UTC().Format(time.RFC3339)) + params.Set("includeMovie", starr.Str(includeMovie)) + + if eventType != "" { + params.Set("eventType", eventType) + } + + var output []*HistoryRecord + + req := starr.Request{URI: path.Join(bpHistory, "since"), Query: params} + if err := r.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return output, nil +} + // Fail marks the given history item as failed by id. func (r *Radarr) Fail(historyID int64) error { return r.FailContext(context.Background(), historyID) diff --git a/radarr/indexerflag.go b/radarr/indexerflag.go new file mode 100644 index 00000000..0f4ee4ce --- /dev/null +++ b/radarr/indexerflag.go @@ -0,0 +1,34 @@ +package radarr + +import ( + "context" + "fmt" + + "golift.io/starr" +) + +const bpIndexerFlag = APIver + "/indexerflag" + +// IndexerFlag is the /api/v3/indexerflag resource. +type IndexerFlag struct { + ID int `json:"id"` + Name string `json:"name,omitempty"` + NameLower string `json:"nameLower,omitempty"` +} + +// GetIndexerFlags returns all indexer flags. +func (r *Radarr) GetIndexerFlags() ([]*IndexerFlag, error) { + return r.GetIndexerFlagsContext(context.Background()) +} + +// GetIndexerFlagsContext returns all indexer flags. +func (r *Radarr) GetIndexerFlagsContext(ctx context.Context) ([]*IndexerFlag, error) { + var output []*IndexerFlag + + req := starr.Request{URI: bpIndexerFlag} + if err := r.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return output, nil +} diff --git a/radarr/language.go b/radarr/language.go new file mode 100644 index 00000000..6af7ef13 --- /dev/null +++ b/radarr/language.go @@ -0,0 +1,51 @@ +package radarr + +import ( + "context" + "fmt" + "path" + + "golift.io/starr" +) + +const bpLanguage = APIver + "/language" + +// Language is an item from /api/v3/language. +type Language struct { + ID int `json:"id"` + Name string `json:"name,omitempty"` +} + +// GetLanguages returns all movie languages. +func (r *Radarr) GetLanguages() ([]*Language, error) { + return r.GetLanguagesContext(context.Background()) +} + +// GetLanguagesContext returns all movie languages. +func (r *Radarr) GetLanguagesContext(ctx context.Context) ([]*Language, error) { + var output []*Language + + req := starr.Request{URI: bpLanguage} + if err := r.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return output, nil +} + +// GetLanguage returns a single language by id. +func (r *Radarr) GetLanguage(id int) (*Language, error) { + return r.GetLanguageContext(context.Background(), id) +} + +// GetLanguageContext returns a single language by id. +func (r *Radarr) GetLanguageContext(ctx context.Context, id int) (*Language, error) { + var output Language + + req := starr.Request{URI: path.Join(bpLanguage, starr.Str(id))} + if err := r.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return &output, nil +} diff --git a/radarr/movie.go b/radarr/movie.go index 32c15b29..48161ed5 100644 --- a/radarr/movie.go +++ b/radarr/movie.go @@ -49,7 +49,7 @@ type Movie struct { Added time.Time `json:"added,omitzero"` Ratings starr.OpenRatings `json:"ratings,omitempty"` MovieFile *MovieFile `json:"movieFile,omitempty"` - Collection *Collection `json:"collection,omitempty"` + Collection *MovieCollection `json:"collection,omitempty"` HasFile bool `json:"hasFile,omitempty"` IsAvailable bool `json:"isAvailable,omitempty"` Monitored bool `json:"monitored"` @@ -58,8 +58,8 @@ type Movie struct { AddOptions *AddMovieOptions `json:"addOptions,omitempty"` // only available upon adding a movie. } -// Collection belongs to a Movie. -type Collection struct { +// MovieCollection is the collection summary embedded in a Movie payload. +type MovieCollection struct { Name string `json:"name"` TmdbID int64 `json:"tmdbId"` Images []*starr.Image `json:"images"` @@ -292,3 +292,25 @@ func (r *Radarr) DeleteMovieContext(ctx context.Context, movieID int64, deleteFi return nil } + +// ImportMovies imports movies from the provided resources (POST /movie/import). +func (r *Radarr) ImportMovies(movies []*Movie) ([]*Movie, error) { + return r.ImportMoviesContext(context.Background(), movies) +} + +// ImportMoviesContext imports movies from the provided resources. +func (r *Radarr) ImportMoviesContext(ctx context.Context, movies []*Movie) ([]*Movie, error) { + var body bytes.Buffer + if err := json.NewEncoder(&body).Encode(movies); err != nil { + return nil, fmt.Errorf("json.Marshal(%s): %w", path.Join(bpMovie, "import"), err) + } + + var output []*Movie + + req := starr.Request{URI: path.Join(bpMovie, "import"), Body: &body} + if err := r.PostInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Post(%s): %w", &req, err) + } + + return output, nil +} diff --git a/radarr/parse.go b/radarr/parse.go new file mode 100644 index 00000000..46502721 --- /dev/null +++ b/radarr/parse.go @@ -0,0 +1,41 @@ +package radarr + +import ( + "context" + "fmt" + "net/url" + + "golift.io/starr" +) + +const bpParse = APIver + "/parse" + +// ParseOutput is returned from GET /api/v3/parse. +type ParseOutput struct { + CustomFormats []*CustomFormatOutput `json:"customFormats,omitempty"` + CustomFormatScore int64 `json:"customFormatScore"` + Languages []*starr.Value `json:"languages,omitempty"` + ID int64 `json:"id"` + Title string `json:"title,omitempty"` + Movie *Movie `json:"movie,omitempty"` + ParsedMovieInfo map[string]any `json:"parsedMovieInfo,omitempty"` +} + +// Parse resolves a release title into parsed movie metadata. +func (r *Radarr) Parse(title string) (*ParseOutput, error) { + return r.ParseContext(context.Background(), title) +} + +// ParseContext resolves a release title into parsed movie metadata. +func (r *Radarr) ParseContext(ctx context.Context, title string) (*ParseOutput, error) { + var output *ParseOutput + + req := starr.Request{URI: bpParse, Query: make(url.Values)} + req.Query.Set("title", title) + + if err := r.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return output, nil +} diff --git a/radarr/qualityprofile.go b/radarr/qualityprofile.go index a9b867e5..fe56ead8 100644 --- a/radarr/qualityprofile.go +++ b/radarr/qualityprofile.go @@ -60,6 +60,23 @@ func (r *Radarr) GetQualityProfileContext(ctx context.Context, profileID int64) return &output, nil } +// GetQualityProfileSchema returns the template/schema quality profiles. +func (r *Radarr) GetQualityProfileSchema() ([]*QualityProfile, error) { + return r.GetQualityProfileSchemaContext(context.Background()) +} + +// GetQualityProfileSchemaContext returns the template/schema quality profiles. +func (r *Radarr) GetQualityProfileSchemaContext(ctx context.Context) ([]*QualityProfile, error) { + var output []*QualityProfile + + req := starr.Request{URI: path.Join(bpQualityProfile, "schema")} + if err := r.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return output, nil +} + // AddQualityProfile updates a quality profile in place. func (r *Radarr) AddQualityProfile(profile *QualityProfile) (*QualityProfile, error) { return r.AddQualityProfileContext(context.Background(), profile) diff --git a/radarr/system.go b/radarr/system.go index 241938d0..1bb6c0e2 100644 --- a/radarr/system.go +++ b/radarr/system.go @@ -1,12 +1,17 @@ package radarr import ( + "bytes" "context" "fmt" + "io" + "mime/multipart" + "net/http" "path" "time" "golift.io/starr" + "golift.io/starr/starrshared" ) const bpSystem = APIver + "/system" @@ -79,3 +84,152 @@ func (r *Radarr) GetBackupFilesContext(ctx context.Context) ([]*starr.BackupFile return output, nil } + +// SystemTask is a scheduled task from /api/v3/system/task. +type SystemTask = starrshared.SystemTask + +// BackupRestoreResponse is returned when restoring a backup. +type BackupRestoreResponse = starrshared.BackupRestoreResponse + +// DeleteBackup deletes a backup file by ID. +func (r *Radarr) DeleteBackup(id int64) error { + return r.DeleteBackupContext(context.Background(), id) +} + +// DeleteBackupContext deletes a backup file by ID. +func (r *Radarr) DeleteBackupContext(ctx context.Context, id int64) error { + req := starr.Request{URI: path.Join(bpSystem, "backup", starr.Str(id))} + if err := r.DeleteAny(ctx, req); err != nil { + return fmt.Errorf("api.Delete(%s): %w", &req, err) + } + + return nil +} + +// RestoreBackup restores an on-disk backup by ID. +func (r *Radarr) RestoreBackup(id int64) (*BackupRestoreResponse, error) { + return r.RestoreBackupContext(context.Background(), id) +} + +// RestoreBackupContext restores an on-disk backup by ID. +func (r *Radarr) RestoreBackupContext(ctx context.Context, id int64) (*BackupRestoreResponse, error) { + var output BackupRestoreResponse + + req := starr.Request{URI: path.Join(bpSystem, "backup", "restore", starr.Str(id))} + if err := r.PostInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Post(%s): %w", &req, err) + } + + return &output, nil +} + +// RestoreBackupUpload uploads a backup archive and restores it. +func (r *Radarr) RestoreBackupUpload(filename string, file io.Reader) (*BackupRestoreResponse, error) { + return r.RestoreBackupUploadContext(context.Background(), filename, file) +} + +// RestoreBackupUploadContext uploads a backup archive and restores it. +func (r *Radarr) RestoreBackupUploadContext( + ctx context.Context, filename string, file io.Reader, +) (*BackupRestoreResponse, error) { + var buf bytes.Buffer + + writer := multipart.NewWriter(&buf) + + part, err := writer.CreateFormFile("file", filename) + if err != nil { + return nil, fmt.Errorf("creating multipart form: %w", err) + } + + if _, err = io.Copy(part, file); err != nil { + return nil, fmt.Errorf("writing backup to multipart form: %w", err) + } + + if err = writer.Close(); err != nil { + return nil, fmt.Errorf("closing multipart writer: %w", err) + } + + var output BackupRestoreResponse + + hdr := make(http.Header) + hdr.Set("Content-Type", writer.FormDataContentType()) + + req := starr.Request{ + URI: path.Join(bpSystem, "backup", "restore", "upload"), + Body: &buf, + Headers: hdr, + } + if err := r.PostInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Post(%s): %w", &req, err) + } + + return &output, nil +} + +// Restart tells Radarr to restart. +func (r *Radarr) Restart() error { + return r.RestartContext(context.Background()) +} + +// RestartContext tells Radarr to restart. +func (r *Radarr) RestartContext(ctx context.Context) error { + var output any + + req := starr.Request{URI: path.Join(bpSystem, "restart")} + if err := r.PostInto(ctx, req, &output); err != nil { + return fmt.Errorf("api.Post(%s): %w", &req, err) + } + + return nil +} + +// Shutdown tells Radarr to shut down. +func (r *Radarr) Shutdown() error { + return r.ShutdownContext(context.Background()) +} + +// ShutdownContext tells Radarr to shut down. +func (r *Radarr) ShutdownContext(ctx context.Context) error { + var output any + + req := starr.Request{URI: path.Join(bpSystem, "shutdown")} + if err := r.PostInto(ctx, req, &output); err != nil { + return fmt.Errorf("api.Post(%s): %w", &req, err) + } + + return nil +} + +// GetSystemTasks returns all scheduled tasks. +func (r *Radarr) GetSystemTasks() ([]*SystemTask, error) { + return r.GetSystemTasksContext(context.Background()) +} + +// GetSystemTasksContext returns all scheduled tasks. +func (r *Radarr) GetSystemTasksContext(ctx context.Context) ([]*SystemTask, error) { + var output []*SystemTask + + req := starr.Request{URI: path.Join(bpSystem, "task")} + if err := r.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return output, nil +} + +// GetSystemTask returns a single scheduled task. +func (r *Radarr) GetSystemTask(id int64) (*SystemTask, error) { + return r.GetSystemTaskContext(context.Background(), id) +} + +// GetSystemTaskContext returns a single scheduled task. +func (r *Radarr) GetSystemTaskContext(ctx context.Context, id int64) (*SystemTask, error) { + var output SystemTask + + req := starr.Request{URI: path.Join(bpSystem, "task", starr.Str(id))} + if err := r.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return &output, nil +} diff --git a/radarr/tag.go b/radarr/tag.go index 58025084..430f0485 100644 --- a/radarr/tag.go +++ b/radarr/tag.go @@ -104,3 +104,51 @@ func (r *Radarr) DeleteTagContext(ctx context.Context, tagID int) error { return nil } + +// TagDetails is the /api/v3/tag/detail resource. +type TagDetails struct { + ID int `json:"id"` + Label string `json:"label,omitempty"` + DelayProfileIDs []int `json:"delayProfileIds,omitempty"` + ImportListIDs []int `json:"importListIds,omitempty"` + NotificationIDs []int `json:"notificationIds,omitempty"` + IndexerIDs []int `json:"indexerIds,omitempty"` + DownloadClientIDs []int `json:"downloadClientIds,omitempty"` + AutoTagIDs []int `json:"autoTagIds,omitempty"` + MovieIDs []int `json:"movieIds,omitempty"` + IndexerProxyIDs []int `json:"indexerProxyIds,omitempty"` +} + +// GetTagDetails returns tag usage details for all tags. +func (r *Radarr) GetTagDetails() ([]*TagDetails, error) { + return r.GetTagDetailsContext(context.Background()) +} + +// GetTagDetailsContext returns tag usage details for all tags. +func (r *Radarr) GetTagDetailsContext(ctx context.Context) ([]*TagDetails, error) { + var output []*TagDetails + + req := starr.Request{URI: path.Join(bpTag, "detail")} + if err := r.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return output, nil +} + +// GetTagDetail returns tag usage details for a single tag. +func (r *Radarr) GetTagDetail(tagID int) (*TagDetails, error) { + return r.GetTagDetailContext(context.Background(), tagID) +} + +// GetTagDetailContext returns tag usage details for a single tag. +func (r *Radarr) GetTagDetailContext(ctx context.Context, tagID int) (*TagDetails, error) { + var output TagDetails + + req := starr.Request{URI: path.Join(bpTag, "detail", starr.Str(tagID))} + if err := r.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return &output, nil +} diff --git a/radarr/update.go b/radarr/update.go new file mode 100644 index 00000000..debebea7 --- /dev/null +++ b/radarr/update.go @@ -0,0 +1,34 @@ +package radarr + +import ( + "context" + "fmt" + + "golift.io/starr" + "golift.io/starr/starrshared" +) + +const bpUpdate = APIver + "/update" + +// UpdateChanges is the change log embedded in Update. +type UpdateChanges = starrshared.UpdateChanges + +// Update is one available or installed update from /api/v3/update. +type Update = starrshared.Update + +// GetUpdates returns available application updates. +func (r *Radarr) GetUpdates() ([]*Update, error) { + return r.GetUpdatesContext(context.Background()) +} + +// GetUpdatesContext returns available application updates. +func (r *Radarr) GetUpdatesContext(ctx context.Context) ([]*Update, error) { + var output []*Update + + req := starr.Request{URI: bpUpdate} + if err := r.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return output, nil +} diff --git a/radarr/wanted.go b/radarr/wanted.go new file mode 100644 index 00000000..10283fe5 --- /dev/null +++ b/radarr/wanted.go @@ -0,0 +1,69 @@ +package radarr + +import ( + "context" + "fmt" + "path" + + "golift.io/starr" +) + +const bpWanted = APIver + "/wanted" + +// WantedMoviesPage is a paged list of movies from /api/v3/wanted/missing or /wanted/cutoff. +type WantedMoviesPage struct { + Page int `json:"page"` + PageSize int `json:"pageSize"` + SortKey string `json:"sortKey,omitempty"` + SortDirection string `json:"sortDirection,omitempty"` + TotalRecords int `json:"totalRecords"` + Records []*Movie `json:"records"` +} + +func wantedPageParams(params *starr.PageReq) *starr.PageReq { + if params == nil { + return &starr.PageReq{} + } + + return params +} + +// GetWantedMissingPage returns a page of missing movies. +func (r *Radarr) GetWantedMissingPage(params *starr.PageReq) (*WantedMoviesPage, error) { + return r.GetWantedMissingPageContext(context.Background(), params) +} + +// GetWantedMissingPageContext returns a page of missing movies. +func (r *Radarr) GetWantedMissingPageContext(ctx context.Context, params *starr.PageReq) (*WantedMoviesPage, error) { + var output WantedMoviesPage + + p := wantedPageParams(params) + p.CheckSet("sortKey", "releaseDate") + + req := starr.Request{URI: path.Join(bpWanted, "missing"), Query: p.Params()} + if err := r.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return &output, nil +} + +// GetWantedCutoffPage returns a page of movies past quality cutoff. +func (r *Radarr) GetWantedCutoffPage(params *starr.PageReq) (*WantedMoviesPage, error) { + return r.GetWantedCutoffPageContext(context.Background(), params) +} + +// GetWantedCutoffPageContext returns a page of movies past quality cutoff. +func (r *Radarr) GetWantedCutoffPageContext(ctx context.Context, params *starr.PageReq) (*WantedMoviesPage, error) { + var output WantedMoviesPage + + p := wantedPageParams(params) + p.CheckSet("sortKey", "releaseDate") + + req := starr.Request{URI: path.Join(bpWanted, "cutoff"), Query: p.Params()} + if err := r.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return &output, nil +} diff --git a/readarr/author.go b/readarr/author.go index afeb6294..ee5c87d7 100644 --- a/readarr/author.go +++ b/readarr/author.go @@ -14,6 +14,71 @@ import ( const bpAuthor = APIver + "/author" +// GetAuthors returns all authors in the library. +func (r *Readarr) GetAuthors() ([]*Author, error) { + return r.GetAuthorsContext(context.Background()) +} + +// GetAuthorsContext returns all authors in the library. +func (r *Readarr) GetAuthorsContext(ctx context.Context) ([]*Author, error) { + var output []*Author + + req := starr.Request{URI: bpAuthor, Query: make(url.Values)} + if err := r.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return output, nil +} + +// AddAuthor adds a new author to Readarr. +func (r *Readarr) AddAuthor(author *Author) (*Author, error) { + return r.AddAuthorContext(context.Background(), author) +} + +// AddAuthorContext adds a new author to Readarr. +func (r *Readarr) AddAuthorContext(ctx context.Context, author *Author) (*Author, error) { + var body bytes.Buffer + if err := json.NewEncoder(&body).Encode(author); err != nil { + return nil, fmt.Errorf("json.Marshal(%s): %w", bpAuthor, err) + } + + var output Author + + req := starr.Request{URI: bpAuthor, Query: make(url.Values), Body: &body} + if err := r.PostInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Post(%s): %w", &req, err) + } + + return &output, nil +} + +// LookupAuthor searches for authors matching the specified search term. +func (r *Readarr) LookupAuthor(term string) ([]*Author, error) { + return r.LookupAuthorContext(context.Background(), term) +} + +// LookupAuthorContext searches for authors matching the specified search term. +func (r *Readarr) LookupAuthorContext(ctx context.Context, term string) ([]*Author, error) { + var output []*Author + + if term == "" { + return output, nil + } + + req := starr.Request{ + URI: path.Join(bpAuthor, "lookup"), + Query: make(url.Values), + } + req.Query.Set("term", term) + + if err := r.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return output, nil +} + // Author is the /api/v1/author endpoint. type Author struct { ID int64 `json:"id"` diff --git a/readarr/autotagging.go b/readarr/autotagging.go new file mode 100644 index 00000000..3d4832b3 --- /dev/null +++ b/readarr/autotagging.go @@ -0,0 +1,130 @@ +package readarr + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "path" + + "golift.io/starr" + "golift.io/starr/starrshared" +) + +const bpAutoTagging = APIver + "/autotagging" + +// AutoTagging is the /api/v1/autotagging resource. +type AutoTagging = starrshared.AutoTagging + +// AutoTaggingSpecification is one rule inside an AutoTagging definition. +type AutoTaggingSpecification = starrshared.AutoTaggingSpecification + +// GetAutoTaggings returns all auto tagging configurations. +func (r *Readarr) GetAutoTaggings() ([]*AutoTagging, error) { + return r.GetAutoTaggingsContext(context.Background()) +} + +// GetAutoTaggingsContext returns all auto tagging configurations. +func (r *Readarr) GetAutoTaggingsContext(ctx context.Context) ([]*AutoTagging, error) { + var output []*AutoTagging + + req := starr.Request{URI: bpAutoTagging} + if err := r.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return output, nil +} + +// GetAutoTagging returns a single auto tagging configuration. +func (r *Readarr) GetAutoTagging(id int) (*AutoTagging, error) { + return r.GetAutoTaggingContext(context.Background(), id) +} + +// GetAutoTaggingContext returns a single auto tagging configuration. +func (r *Readarr) GetAutoTaggingContext(ctx context.Context, id int) (*AutoTagging, error) { + var output AutoTagging + + req := starr.Request{URI: path.Join(bpAutoTagging, starr.Str(id))} + if err := r.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return &output, nil +} + +// GetAutoTaggingSchema returns the specification schema templates for auto tagging. +func (r *Readarr) GetAutoTaggingSchema() ([]*AutoTaggingSpecification, error) { + return r.GetAutoTaggingSchemaContext(context.Background()) +} + +// GetAutoTaggingSchemaContext returns the specification schema templates for auto tagging. +func (r *Readarr) GetAutoTaggingSchemaContext(ctx context.Context) ([]*AutoTaggingSpecification, error) { + var output []*AutoTaggingSpecification + + req := starr.Request{URI: path.Join(bpAutoTagging, "schema")} + if err := r.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return output, nil +} + +// AddAutoTagging creates an auto tagging configuration. +func (r *Readarr) AddAutoTagging(in *AutoTagging) (*AutoTagging, error) { + return r.AddAutoTaggingContext(context.Background(), in) +} + +// AddAutoTaggingContext creates an auto tagging configuration. +func (r *Readarr) AddAutoTaggingContext(ctx context.Context, in *AutoTagging) (*AutoTagging, error) { + var output AutoTagging + + var body bytes.Buffer + if err := json.NewEncoder(&body).Encode(in); err != nil { + return nil, fmt.Errorf("json.Marshal(%s): %w", bpAutoTagging, err) + } + + req := starr.Request{URI: bpAutoTagging, Body: &body} + if err := r.PostInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Post(%s): %w", &req, err) + } + + return &output, nil +} + +// UpdateAutoTagging updates an auto tagging configuration. +func (r *Readarr) UpdateAutoTagging(in *AutoTagging) (*AutoTagging, error) { + return r.UpdateAutoTaggingContext(context.Background(), in) +} + +// UpdateAutoTaggingContext updates an auto tagging configuration. +func (r *Readarr) UpdateAutoTaggingContext(ctx context.Context, input *AutoTagging) (*AutoTagging, error) { + var output AutoTagging + + var body bytes.Buffer + if err := json.NewEncoder(&body).Encode(input); err != nil { + return nil, fmt.Errorf("json.Marshal(%s): %w", bpAutoTagging, err) + } + + req := starr.Request{URI: path.Join(bpAutoTagging, starr.Str(input.ID)), Body: &body} + if err := r.PutInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Put(%s): %w", &req, err) + } + + return &output, nil +} + +// DeleteAutoTagging deletes an auto tagging configuration. +func (r *Readarr) DeleteAutoTagging(id int) error { + return r.DeleteAutoTaggingContext(context.Background(), id) +} + +// DeleteAutoTaggingContext deletes an auto tagging configuration. +func (r *Readarr) DeleteAutoTaggingContext(ctx context.Context, id int) error { + req := starr.Request{URI: path.Join(bpAutoTagging, starr.Str(id))} + if err := r.DeleteAny(ctx, req); err != nil { + return fmt.Errorf("api.Delete(%s): %w", &req, err) + } + + return nil +} diff --git a/readarr/book.go b/readarr/book.go index 38ce6428..b35c7971 100644 --- a/readarr/book.go +++ b/readarr/book.go @@ -242,3 +242,33 @@ func (r *Readarr) DeleteBookContext(ctx context.Context, bookID int64, deleteFil return nil } + +// BooksMonitoredInput is the body for PUT /book/monitor. +type BooksMonitoredInput struct { + BookIDs []int64 `json:"bookIds"` + Monitored bool `json:"monitored"` +} + +// MonitorBooks sets monitored state for the given book IDs. +func (r *Readarr) MonitorBooks(bookIDs []int64, monitored bool) ([]*Book, error) { + return r.MonitorBooksContext(context.Background(), bookIDs, monitored) +} + +// MonitorBooksContext sets monitored state for the given book IDs. +func (r *Readarr) MonitorBooksContext(ctx context.Context, bookIDs []int64, monitored bool) ([]*Book, error) { + in := BooksMonitoredInput{BookIDs: bookIDs, Monitored: monitored} + + var body bytes.Buffer + if err := json.NewEncoder(&body).Encode(&in); err != nil { + return nil, fmt.Errorf("json.Marshal(%s): %w", path.Join(bpBook, "monitor"), err) + } + + var output []*Book + + req := starr.Request{URI: path.Join(bpBook, "monitor"), Body: &body} + if err := r.PutInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Put(%s): %w", &req, err) + } + + return output, nil +} diff --git a/readarr/command.go b/readarr/command.go index 1f994541..bfb8ae29 100644 --- a/readarr/command.go +++ b/readarr/command.go @@ -5,6 +5,7 @@ import ( "context" "encoding/json" "fmt" + "path" "time" "golift.io/starr" @@ -84,3 +85,24 @@ func (r *Readarr) SendCommandContext(ctx context.Context, cmd *CommandRequest) ( return &output, nil } + +// GetCommandStatus returns the status of an already started command. +func (r *Readarr) GetCommandStatus(commandID int64) (*CommandResponse, error) { + return r.GetCommandStatusContext(context.Background(), commandID) +} + +// GetCommandStatusContext returns the status of an already started command. +func (r *Readarr) GetCommandStatusContext(ctx context.Context, commandID int64) (*CommandResponse, error) { + var output CommandResponse + + if commandID == 0 { + return &output, nil + } + + req := starr.Request{URI: path.Join(bpCommand, starr.Str(commandID))} + if err := r.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return &output, nil +} diff --git a/readarr/customfilter.go b/readarr/customfilter.go new file mode 100644 index 00000000..b73312ea --- /dev/null +++ b/readarr/customfilter.go @@ -0,0 +1,110 @@ +package readarr + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "path" + + "golift.io/starr" + "golift.io/starr/starrshared" +) + +const bpCustomFilter = APIver + "/customfilter" + +// CustomFilter is the /api/v1/customfilter resource. +type CustomFilter = starrshared.CustomFilter + +// GetCustomFilters returns all custom filters. +func (r *Readarr) GetCustomFilters() ([]*CustomFilter, error) { + return r.GetCustomFiltersContext(context.Background()) +} + +// GetCustomFiltersContext returns all custom filters. +func (r *Readarr) GetCustomFiltersContext(ctx context.Context) ([]*CustomFilter, error) { + var output []*CustomFilter + + req := starr.Request{URI: bpCustomFilter} + if err := r.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return output, nil +} + +// GetCustomFilter returns a single custom filter. +func (r *Readarr) GetCustomFilter(id int) (*CustomFilter, error) { + return r.GetCustomFilterContext(context.Background(), id) +} + +// GetCustomFilterContext returns a single custom filter. +func (r *Readarr) GetCustomFilterContext(ctx context.Context, id int) (*CustomFilter, error) { + var output CustomFilter + + req := starr.Request{URI: path.Join(bpCustomFilter, starr.Str(id))} + if err := r.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return &output, nil +} + +// AddCustomFilter creates a custom filter. +func (r *Readarr) AddCustomFilter(in *CustomFilter) (*CustomFilter, error) { + return r.AddCustomFilterContext(context.Background(), in) +} + +// AddCustomFilterContext creates a custom filter. +func (r *Readarr) AddCustomFilterContext(ctx context.Context, in *CustomFilter) (*CustomFilter, error) { + var output CustomFilter + + var body bytes.Buffer + if err := json.NewEncoder(&body).Encode(in); err != nil { + return nil, fmt.Errorf("json.Marshal(%s): %w", bpCustomFilter, err) + } + + req := starr.Request{URI: bpCustomFilter, Body: &body} + if err := r.PostInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Post(%s): %w", &req, err) + } + + return &output, nil +} + +// UpdateCustomFilter updates a custom filter. +func (r *Readarr) UpdateCustomFilter(in *CustomFilter) (*CustomFilter, error) { + return r.UpdateCustomFilterContext(context.Background(), in) +} + +// UpdateCustomFilterContext updates a custom filter. +func (r *Readarr) UpdateCustomFilterContext(ctx context.Context, input *CustomFilter) (*CustomFilter, error) { + var output CustomFilter + + var body bytes.Buffer + if err := json.NewEncoder(&body).Encode(input); err != nil { + return nil, fmt.Errorf("json.Marshal(%s): %w", bpCustomFilter, err) + } + + req := starr.Request{URI: path.Join(bpCustomFilter, starr.Str(input.ID)), Body: &body} + if err := r.PutInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Put(%s): %w", &req, err) + } + + return &output, nil +} + +// DeleteCustomFilter deletes a custom filter. +func (r *Readarr) DeleteCustomFilter(id int) error { + return r.DeleteCustomFilterContext(context.Background(), id) +} + +// DeleteCustomFilterContext deletes a custom filter. +func (r *Readarr) DeleteCustomFilterContext(ctx context.Context, id int) error { + req := starr.Request{URI: path.Join(bpCustomFilter, starr.Str(id))} + if err := r.DeleteAny(ctx, req); err != nil { + return fmt.Errorf("api.Delete(%s): %w", &req, err) + } + + return nil +} diff --git a/readarr/delayprofile.go b/readarr/delayprofile.go new file mode 100644 index 00000000..78e64412 --- /dev/null +++ b/readarr/delayprofile.go @@ -0,0 +1,141 @@ +package readarr + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "net/url" + "path" + + "golift.io/starr" +) + +// Define Base Path for Delay Profile calls. +const bpDelayProfile = APIver + "/delayProfile" + +// DelayProfile is the /api/v1/delayprofile endpoint. +type DelayProfile struct { + EnableUsenet bool `json:"enableUsenet,omitempty"` + EnableTorrent bool `json:"enableTorrent,omitempty"` + BypassIfHighestQuality bool `json:"bypassIfHighestQuality,omitempty"` + UsenetDelay int64 `json:"usenetDelay,omitempty"` + TorrentDelay int64 `json:"torrentDelay,omitempty"` + ID int64 `json:"id,omitempty"` + Order int64 `json:"order,omitempty"` + Tags []int `json:"tags"` + PreferredProtocol starr.Protocol `json:"preferredProtocol,omitempty"` +} + +// GetDelayProfiles returns all configured delay profiles. +func (r *Readarr) GetDelayProfiles() ([]*DelayProfile, error) { + return r.GetDelayProfilesContext(context.Background()) +} + +// GetDelayProfilesContext returns all configured delay profiles. +func (r *Readarr) GetDelayProfilesContext(ctx context.Context) ([]*DelayProfile, error) { + var output []*DelayProfile + + req := starr.Request{URI: bpDelayProfile} + if err := r.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return output, nil +} + +// GetDelayProfile returns a single delay profile. +func (r *Readarr) GetDelayProfile(profileID int64) (*DelayProfile, error) { + return r.GetDelayProfileContext(context.Background(), profileID) +} + +// GetDelayProfileContext returns a single delay profile. +func (r *Readarr) GetDelayProfileContext(ctx context.Context, profileID int64) (*DelayProfile, error) { + var output DelayProfile + + req := starr.Request{URI: path.Join(bpDelayProfile, starr.Str(profileID))} + if err := r.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return &output, nil +} + +// AddDelayProfile creates a delay profile. +func (r *Readarr) AddDelayProfile(profile *DelayProfile) (*DelayProfile, error) { + return r.AddDelayProfileContext(context.Background(), profile) +} + +// AddDelayProfileContext creates a delay profile. +func (r *Readarr) AddDelayProfileContext(ctx context.Context, profile *DelayProfile) (*DelayProfile, error) { + var output DelayProfile + + var body bytes.Buffer + if err := json.NewEncoder(&body).Encode(profile); err != nil { + return nil, fmt.Errorf("json.Marshal(%s): %w", bpDelayProfile, err) + } + + req := starr.Request{URI: bpDelayProfile, Body: &body} + if err := r.PostInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Post(%s): %w", &req, err) + } + + return &output, nil +} + +// UpdateDelayProfile updates the delay profile. +func (r *Readarr) UpdateDelayProfile(profile *DelayProfile) (*DelayProfile, error) { + return r.UpdateDelayProfileContext(context.Background(), profile) +} + +// UpdateDelayProfileContext updates the delay profile. +func (r *Readarr) UpdateDelayProfileContext(ctx context.Context, profile *DelayProfile) (*DelayProfile, error) { + var output DelayProfile + + var body bytes.Buffer + if err := json.NewEncoder(&body).Encode(profile); err != nil { + return nil, fmt.Errorf("json.Marshal(%s): %w", bpDelayProfile, err) + } + + req := starr.Request{URI: path.Join(bpDelayProfile, starr.Str(profile.ID)), Body: &body} + if err := r.PutInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Put(%s): %w", &req, err) + } + + return &output, nil +} + +// DeleteDelayProfile removes a single delay profile. +func (r *Readarr) DeleteDelayProfile(profileID int64) error { + return r.DeleteDelayProfileContext(context.Background(), profileID) +} + +// DeleteDelayProfileContext removes a single delay profile. +func (r *Readarr) DeleteDelayProfileContext(ctx context.Context, profileID int64) error { + req := starr.Request{URI: path.Join(bpDelayProfile, starr.Str(profileID))} + if err := r.DeleteAny(ctx, req); err != nil { + return fmt.Errorf("api.Delete(%s): %w", &req, err) + } + + return nil +} + +// ReorderDelayProfile moves a delay profile relative to another profile. +func (r *Readarr) ReorderDelayProfile(id, afterID int64) ([]*DelayProfile, error) { + return r.ReorderDelayProfileContext(context.Background(), id, afterID) +} + +// ReorderDelayProfileContext moves a delay profile relative to another profile. +func (r *Readarr) ReorderDelayProfileContext(ctx context.Context, id, afterID int64) ([]*DelayProfile, error) { + var output []*DelayProfile + + req := starr.Request{ + URI: path.Join(bpDelayProfile, "reorder", starr.Str(id)), + Query: url.Values{"after": []string{starr.Str(afterID)}}, + } + if err := r.PutInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Put(%s): %w", &req, err) + } + + return output, nil +} diff --git a/readarr/diskspace.go b/readarr/diskspace.go new file mode 100644 index 00000000..f6c26a3d --- /dev/null +++ b/readarr/diskspace.go @@ -0,0 +1,31 @@ +package readarr + +import ( + "context" + "fmt" + + "golift.io/starr" + "golift.io/starr/starrshared" +) + +const bpDiskSpace = APIver + "/diskspace" + +// DiskSpace is the /api/v1/diskspace resource. +type DiskSpace = starrshared.DiskSpace + +// GetDiskSpace returns disk space information for Readarr paths. +func (r *Readarr) GetDiskSpace() ([]*DiskSpace, error) { + return r.GetDiskSpaceContext(context.Background()) +} + +// GetDiskSpaceContext returns disk space information for Readarr paths. +func (r *Readarr) GetDiskSpaceContext(ctx context.Context) ([]*DiskSpace, error) { + var output []*DiskSpace + + req := starr.Request{URI: bpDiskSpace} + if err := r.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return output, nil +} diff --git a/readarr/health.go b/readarr/health.go new file mode 100644 index 00000000..65d8f5f9 --- /dev/null +++ b/readarr/health.go @@ -0,0 +1,31 @@ +package readarr + +import ( + "context" + "fmt" + + "golift.io/starr" + "golift.io/starr/starrshared" +) + +const bpHealth = APIver + "/health" + +// Health is the /api/v1/health resource. +type Health = starrshared.Health + +// GetHealth returns current health check messages. +func (r *Readarr) GetHealth() ([]*Health, error) { + return r.GetHealthContext(context.Background()) +} + +// GetHealthContext returns current health check messages. +func (r *Readarr) GetHealthContext(ctx context.Context) ([]*Health, error) { + var output []*Health + + req := starr.Request{URI: bpHealth} + if err := r.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return output, nil +} diff --git a/readarr/parse.go b/readarr/parse.go new file mode 100644 index 00000000..3251d4bc --- /dev/null +++ b/readarr/parse.go @@ -0,0 +1,40 @@ +package readarr + +import ( + "context" + "fmt" + "net/url" + + "golift.io/starr" +) + +const bpParse = APIver + "/parse" + +// ParseOutput is returned from GET /api/v1/parse. +type ParseOutput struct { + ID int64 `json:"id"` + Title string `json:"title,omitempty"` + Author *Author `json:"author,omitempty"` + Books []*Book `json:"books,omitempty"` + CustomFormats []any `json:"customFormats,omitempty"` + CustomFormatScore int64 `json:"customFormatScore"` +} + +// Parse resolves a release title into parsed book metadata. +func (r *Readarr) Parse(title string) (*ParseOutput, error) { + return r.ParseContext(context.Background(), title) +} + +// ParseContext resolves a release title into parsed book metadata. +func (r *Readarr) ParseContext(ctx context.Context, title string) (*ParseOutput, error) { + var output *ParseOutput + + req := starr.Request{URI: bpParse, Query: make(url.Values)} + req.Query.Set("title", title) + + if err := r.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return output, nil +} diff --git a/readarr/qualitydefinition.go b/readarr/qualitydefinition.go new file mode 100644 index 00000000..9c7017ce --- /dev/null +++ b/readarr/qualitydefinition.go @@ -0,0 +1,109 @@ +package readarr + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "path" + + "golift.io/starr" +) + +// QualityDefinition is the /api/v1/qualitydefinition endpoint. +type QualityDefinition struct { + ID int64 `json:"id,omitempty"` + Weight int64 `json:"weight"` // This should not be changed. + MinSize float64 `json:"minSize"` + MaxSize float64 `json:"maxSize"` + PrefSize float64 `json:"preferredSize"` + Title string `json:"title"` + Quality *starr.BaseQuality `json:"quality"` +} + +// Define Base Path for Quality Definition calls. +const bpQualityDefinition = APIver + "/qualityDefinition" + +// GetQualityDefinitions returns all configured quality definitions. +func (r *Readarr) GetQualityDefinitions() ([]*QualityDefinition, error) { + return r.GetQualityDefinitionsContext(context.Background()) +} + +// GetQualityDefinitionsContext returns all configured quality definitions. +func (r *Readarr) GetQualityDefinitionsContext(ctx context.Context) ([]*QualityDefinition, error) { + var output []*QualityDefinition + + req := starr.Request{URI: bpQualityDefinition} + if err := r.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return output, nil +} + +// GetQualityDefinition returns a single quality definition. +func (r *Readarr) GetQualityDefinition(qualityDefinitionID int64) (*QualityDefinition, error) { + return r.GetQualityDefinitionContext(context.Background(), qualityDefinitionID) +} + +// GetQualityDefinitionContext returns a single quality definition. +func (r *Readarr) GetQualityDefinitionContext(ctx context.Context, qdID int64) (*QualityDefinition, error) { + var output QualityDefinition + + req := starr.Request{URI: path.Join(bpQualityDefinition, starr.Str(qdID))} + if err := r.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return &output, nil +} + +// UpdateQualityDefinition updates a quality definition. +func (r *Readarr) UpdateQualityDefinition(definition *QualityDefinition) (*QualityDefinition, error) { + return r.UpdateQualityDefinitionContext(context.Background(), definition) +} + +// UpdateQualityDefinitionContext updates a quality definition. +func (r *Readarr) UpdateQualityDefinitionContext( + ctx context.Context, + definition *QualityDefinition, +) (*QualityDefinition, error) { + var output QualityDefinition + + var body bytes.Buffer + if err := json.NewEncoder(&body).Encode(definition); err != nil { + return nil, fmt.Errorf("json.Marshal(%s): %w", bpQualityDefinition, err) + } + + req := starr.Request{URI: path.Join(bpQualityDefinition, starr.Str(definition.ID)), Body: &body} + if err := r.PutInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Put(%s): %w", &req, err) + } + + return &output, nil +} + +// UpdateQualityDefinitions updates all quality definitions. +func (r *Readarr) UpdateQualityDefinitions(definition []*QualityDefinition) ([]*QualityDefinition, error) { + return r.UpdateQualityDefinitionsContext(context.Background(), definition) +} + +// UpdateQualityDefinitionsContext updates all quality definitions. +func (r *Readarr) UpdateQualityDefinitionsContext( + ctx context.Context, + definition []*QualityDefinition, +) ([]*QualityDefinition, error) { + var output []*QualityDefinition + + var body bytes.Buffer + if err := json.NewEncoder(&body).Encode(definition); err != nil { + return nil, fmt.Errorf("json.Marshal(%s): %w", bpQualityDefinition, err) + } + + req := starr.Request{URI: path.Join(bpQualityDefinition, "update"), Body: &body} + if err := r.PutInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Put(%s): %w", &req, err) + } + + return output, nil +} diff --git a/readarr/qualityprofile.go b/readarr/qualityprofile.go index 39bb1e30..2c847a58 100644 --- a/readarr/qualityprofile.go +++ b/readarr/qualityprofile.go @@ -42,6 +42,23 @@ func (r *Readarr) GetQualityProfilesContext(ctx context.Context) ([]*QualityProf return output, nil } +// GetQualityProfile returns a single quality profile. +func (r *Readarr) GetQualityProfile(profileID int64) (*QualityProfile, error) { + return r.GetQualityProfileContext(context.Background(), profileID) +} + +// GetQualityProfileContext returns a single quality profile. +func (r *Readarr) GetQualityProfileContext(ctx context.Context, profileID int64) (*QualityProfile, error) { + var output QualityProfile + + req := starr.Request{URI: path.Join(bpQualityProfile, starr.Str(profileID))} + if err := r.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return &output, nil +} + // AddQualityProfile updates a quality profile in place. func (r *Readarr) AddQualityProfile(profile *QualityProfile) (int64, error) { return r.AddQualityProfileContext(context.Background(), profile) diff --git a/readarr/system.go b/readarr/system.go index 93e06612..d0c878d8 100644 --- a/readarr/system.go +++ b/readarr/system.go @@ -1,12 +1,17 @@ package readarr import ( + "bytes" "context" "fmt" + "io" + "mime/multipart" + "net/http" "path" "time" "golift.io/starr" + "golift.io/starr/starrshared" ) const bpSystem = APIver + "/system" @@ -81,3 +86,152 @@ func (r *Readarr) GetBackupFilesContext(ctx context.Context) ([]*starr.BackupFil return output, nil } + +// SystemTask is a scheduled task from /api/v1/system/task. +type SystemTask = starrshared.SystemTask + +// BackupRestoreResponse is returned when restoring a backup. +type BackupRestoreResponse = starrshared.BackupRestoreResponse + +// DeleteBackup deletes a backup file by ID. +func (r *Readarr) DeleteBackup(id int64) error { + return r.DeleteBackupContext(context.Background(), id) +} + +// DeleteBackupContext deletes a backup file by ID. +func (r *Readarr) DeleteBackupContext(ctx context.Context, id int64) error { + req := starr.Request{URI: path.Join(bpSystem, "backup", starr.Str(id))} + if err := r.DeleteAny(ctx, req); err != nil { + return fmt.Errorf("api.Delete(%s): %w", &req, err) + } + + return nil +} + +// RestoreBackup restores an on-disk backup by ID. +func (r *Readarr) RestoreBackup(id int64) (*BackupRestoreResponse, error) { + return r.RestoreBackupContext(context.Background(), id) +} + +// RestoreBackupContext restores an on-disk backup by ID. +func (r *Readarr) RestoreBackupContext(ctx context.Context, id int64) (*BackupRestoreResponse, error) { + var output BackupRestoreResponse + + req := starr.Request{URI: path.Join(bpSystem, "backup", "restore", starr.Str(id))} + if err := r.PostInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Post(%s): %w", &req, err) + } + + return &output, nil +} + +// RestoreBackupUpload uploads a backup archive and restores it. +func (r *Readarr) RestoreBackupUpload(filename string, file io.Reader) (*BackupRestoreResponse, error) { + return r.RestoreBackupUploadContext(context.Background(), filename, file) +} + +// RestoreBackupUploadContext uploads a backup archive and restores it. +func (r *Readarr) RestoreBackupUploadContext( + ctx context.Context, filename string, file io.Reader, +) (*BackupRestoreResponse, error) { + var buf bytes.Buffer + + writer := multipart.NewWriter(&buf) + + part, err := writer.CreateFormFile("file", filename) + if err != nil { + return nil, fmt.Errorf("creating multipart form: %w", err) + } + + if _, err = io.Copy(part, file); err != nil { + return nil, fmt.Errorf("writing backup to multipart form: %w", err) + } + + if err = writer.Close(); err != nil { + return nil, fmt.Errorf("closing multipart writer: %w", err) + } + + var output BackupRestoreResponse + + hdr := make(http.Header) + hdr.Set("Content-Type", writer.FormDataContentType()) + + req := starr.Request{ + URI: path.Join(bpSystem, "backup", "restore", "upload"), + Body: &buf, + Headers: hdr, + } + if err := r.PostInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Post(%s): %w", &req, err) + } + + return &output, nil +} + +// Restart tells Readarr to restart. +func (r *Readarr) Restart() error { + return r.RestartContext(context.Background()) +} + +// RestartContext tells Readarr to restart. +func (r *Readarr) RestartContext(ctx context.Context) error { + var output any + + req := starr.Request{URI: path.Join(bpSystem, "restart")} + if err := r.PostInto(ctx, req, &output); err != nil { + return fmt.Errorf("api.Post(%s): %w", &req, err) + } + + return nil +} + +// Shutdown tells Readarr to shut down. +func (r *Readarr) Shutdown() error { + return r.ShutdownContext(context.Background()) +} + +// ShutdownContext tells Readarr to shut down. +func (r *Readarr) ShutdownContext(ctx context.Context) error { + var output any + + req := starr.Request{URI: path.Join(bpSystem, "shutdown")} + if err := r.PostInto(ctx, req, &output); err != nil { + return fmt.Errorf("api.Post(%s): %w", &req, err) + } + + return nil +} + +// GetSystemTasks returns all scheduled tasks. +func (r *Readarr) GetSystemTasks() ([]*SystemTask, error) { + return r.GetSystemTasksContext(context.Background()) +} + +// GetSystemTasksContext returns all scheduled tasks. +func (r *Readarr) GetSystemTasksContext(ctx context.Context) ([]*SystemTask, error) { + var output []*SystemTask + + req := starr.Request{URI: path.Join(bpSystem, "task")} + if err := r.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return output, nil +} + +// GetSystemTask returns a single scheduled task. +func (r *Readarr) GetSystemTask(id int64) (*SystemTask, error) { + return r.GetSystemTaskContext(context.Background(), id) +} + +// GetSystemTaskContext returns a single scheduled task. +func (r *Readarr) GetSystemTaskContext(ctx context.Context, id int64) (*SystemTask, error) { + var output SystemTask + + req := starr.Request{URI: path.Join(bpSystem, "task", starr.Str(id))} + if err := r.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return &output, nil +} diff --git a/readarr/tag.go b/readarr/tag.go index 51f04129..90db71bc 100644 --- a/readarr/tag.go +++ b/readarr/tag.go @@ -104,3 +104,51 @@ func (r *Readarr) DeleteTagContext(ctx context.Context, tagID int) error { return nil } + +// TagDetails is the /api/v1/tag/detail resource. +type TagDetails struct { + ID int `json:"id"` + Label string `json:"label,omitempty"` + DelayProfileIDs []int `json:"delayProfileIds,omitempty"` + ImportListIDs []int `json:"importListIds,omitempty"` + NotificationIDs []int `json:"notificationIds,omitempty"` + IndexerIDs []int `json:"indexerIds,omitempty"` + DownloadClientIDs []int `json:"downloadClientIds,omitempty"` + AutoTagIDs []int `json:"autoTagIds,omitempty"` + AuthorIDs []int `json:"authorIds,omitempty"` + IndexerProxyIDs []int `json:"indexerProxyIds,omitempty"` +} + +// GetTagDetails returns tag usage details for all tags. +func (r *Readarr) GetTagDetails() ([]*TagDetails, error) { + return r.GetTagDetailsContext(context.Background()) +} + +// GetTagDetailsContext returns tag usage details for all tags. +func (r *Readarr) GetTagDetailsContext(ctx context.Context) ([]*TagDetails, error) { + var output []*TagDetails + + req := starr.Request{URI: path.Join(bpTag, "detail")} + if err := r.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return output, nil +} + +// GetTagDetail returns tag usage details for a single tag. +func (r *Readarr) GetTagDetail(tagID int) (*TagDetails, error) { + return r.GetTagDetailContext(context.Background(), tagID) +} + +// GetTagDetailContext returns tag usage details for a single tag. +func (r *Readarr) GetTagDetailContext(ctx context.Context, tagID int) (*TagDetails, error) { + var output TagDetails + + req := starr.Request{URI: path.Join(bpTag, "detail", starr.Str(tagID))} + if err := r.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return &output, nil +} diff --git a/readarr/update.go b/readarr/update.go new file mode 100644 index 00000000..d2122472 --- /dev/null +++ b/readarr/update.go @@ -0,0 +1,34 @@ +package readarr + +import ( + "context" + "fmt" + + "golift.io/starr" + "golift.io/starr/starrshared" +) + +const bpUpdate = APIver + "/update" + +// UpdateChanges is the change log embedded in Update. +type UpdateChanges = starrshared.UpdateChanges + +// Update is one available or installed update from /api/v1/update. +type Update = starrshared.Update + +// GetUpdates returns available application updates. +func (r *Readarr) GetUpdates() ([]*Update, error) { + return r.GetUpdatesContext(context.Background()) +} + +// GetUpdatesContext returns available application updates. +func (r *Readarr) GetUpdatesContext(ctx context.Context) ([]*Update, error) { + var output []*Update + + req := starr.Request{URI: bpUpdate} + if err := r.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return output, nil +} diff --git a/readarr/wanted.go b/readarr/wanted.go new file mode 100644 index 00000000..a614a33b --- /dev/null +++ b/readarr/wanted.go @@ -0,0 +1,69 @@ +package readarr + +import ( + "context" + "fmt" + "path" + + "golift.io/starr" +) + +const bpWanted = APIver + "/wanted" + +// WantedBooksPage is a paged list of books from /api/v1/wanted/missing or /wanted/cutoff. +type WantedBooksPage struct { + Page int `json:"page"` + PageSize int `json:"pageSize"` + SortKey string `json:"sortKey,omitempty"` + SortDirection string `json:"sortDirection,omitempty"` + TotalRecords int `json:"totalRecords"` + Records []*Book `json:"records"` +} + +func wantedPageParams(params *starr.PageReq) *starr.PageReq { + if params == nil { + return &starr.PageReq{} + } + + return params +} + +// GetWantedMissingPage returns a page of missing books. +func (r *Readarr) GetWantedMissingPage(params *starr.PageReq) (*WantedBooksPage, error) { + return r.GetWantedMissingPageContext(context.Background(), params) +} + +// GetWantedMissingPageContext returns a page of missing books. +func (r *Readarr) GetWantedMissingPageContext(ctx context.Context, params *starr.PageReq) (*WantedBooksPage, error) { + var output WantedBooksPage + + p := wantedPageParams(params) + p.CheckSet("sortKey", "releaseDate") + + req := starr.Request{URI: path.Join(bpWanted, "missing"), Query: p.Params()} + if err := r.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return &output, nil +} + +// GetWantedCutoffPage returns a page of books past quality cutoff. +func (r *Readarr) GetWantedCutoffPage(params *starr.PageReq) (*WantedBooksPage, error) { + return r.GetWantedCutoffPageContext(context.Background(), params) +} + +// GetWantedCutoffPageContext returns a page of books past quality cutoff. +func (r *Readarr) GetWantedCutoffPageContext(ctx context.Context, params *starr.PageReq) (*WantedBooksPage, error) { + var output WantedBooksPage + + p := wantedPageParams(params) + p.CheckSet("sortKey", "releaseDate") + + req := starr.Request{URI: path.Join(bpWanted, "cutoff"), Query: p.Params()} + if err := r.GetInto(ctx, req, &output); err != nil { + return nil, fmt.Errorf("api.Get(%s): %w", &req, err) + } + + return &output, nil +} diff --git a/shared.go b/shared.go index e6574bb3..8f5b6ee6 100644 --- a/shared.go +++ b/shared.go @@ -9,7 +9,7 @@ import ( "time" ) -/* This file contains shared structs or constants for all the *arr apps. */ +/* This file contains shared structs and constants for all the Starr apps. */ // CalendarTimeFilterFormat is the Go time format the calendar expects the filter to be in. const CalendarTimeFilterFormat = "2006-01-02T03:04:05.000Z" diff --git a/sonarr/autotagging.go b/sonarr/autotagging.go index 0c1283d8..7b46d9c6 100644 --- a/sonarr/autotagging.go +++ b/sonarr/autotagging.go @@ -8,29 +8,16 @@ import ( "path" "golift.io/starr" + "golift.io/starr/starrshared" ) const bpAutoTagging = APIver + "/autotagging" // AutoTagging is the /api/v3/autotagging resource. -type AutoTagging struct { - ID int `json:"id,omitempty"` - Name string `json:"name,omitempty"` - RemoveTagsAutomatically bool `json:"removeTagsAutomatically"` - Tags []int `json:"tags,omitempty"` - Specifications []*AutoTaggingSpecification `json:"specifications,omitempty"` -} +type AutoTagging = starrshared.AutoTagging // AutoTaggingSpecification is one rule inside an AutoTagging definition. -type AutoTaggingSpecification struct { - ID int `json:"id,omitempty"` - Name string `json:"name,omitempty"` - Implementation string `json:"implementation,omitempty"` - ImplementationName string `json:"implementationName,omitempty"` - Negate bool `json:"negate"` - Required bool `json:"required"` - Fields []*starr.FieldInput `json:"fields,omitempty"` -} +type AutoTaggingSpecification = starrshared.AutoTaggingSpecification // GetAutoTaggings returns all auto tagging configurations. func (s *Sonarr) GetAutoTaggings() ([]*AutoTagging, error) { diff --git a/sonarr/customfilter.go b/sonarr/customfilter.go index 7dc13569..83ae74d1 100644 --- a/sonarr/customfilter.go +++ b/sonarr/customfilter.go @@ -8,17 +8,13 @@ import ( "path" "golift.io/starr" + "golift.io/starr/starrshared" ) const bpCustomFilter = APIver + "/customfilter" // CustomFilter is the /api/v3/customfilter resource. -type CustomFilter struct { - ID int `json:"id,omitempty"` - Type string `json:"type,omitempty"` - Label string `json:"label,omitempty"` - Filters []json.RawMessage `json:"filters,omitempty"` -} +type CustomFilter = starrshared.CustomFilter // GetCustomFilters returns all custom filters. func (s *Sonarr) GetCustomFilters() ([]*CustomFilter, error) { diff --git a/sonarr/diskspace.go b/sonarr/diskspace.go index 94ad6119..3037b164 100644 --- a/sonarr/diskspace.go +++ b/sonarr/diskspace.go @@ -5,18 +5,13 @@ import ( "fmt" "golift.io/starr" + "golift.io/starr/starrshared" ) const bpDiskSpace = APIver + "/diskspace" // DiskSpace is the /api/v3/diskspace resource. -type DiskSpace struct { - ID int `json:"id"` - Path string `json:"path,omitempty"` - Label string `json:"label,omitempty"` - FreeSpace int64 `json:"freeSpace"` - TotalSpace int64 `json:"totalSpace"` -} +type DiskSpace = starrshared.DiskSpace // GetDiskSpace returns disk space information for Sonarr paths. func (s *Sonarr) GetDiskSpace() ([]*DiskSpace, error) { diff --git a/sonarr/health.go b/sonarr/health.go index ab254c0c..c3b8a10d 100644 --- a/sonarr/health.go +++ b/sonarr/health.go @@ -5,18 +5,13 @@ import ( "fmt" "golift.io/starr" + "golift.io/starr/starrshared" ) const bpHealth = APIver + "/health" // Health is the /api/v3/health resource. -type Health struct { - ID int `json:"id"` - Source string `json:"source,omitempty"` - Type string `json:"type,omitempty"` - Message string `json:"message,omitempty"` - WikiURL string `json:"wikiUrl,omitempty"` -} +type Health = starrshared.Health // GetHealth returns current health check messages. func (s *Sonarr) GetHealth() ([]*Health, error) { diff --git a/sonarr/system.go b/sonarr/system.go index aa826500..b5e4b852 100644 --- a/sonarr/system.go +++ b/sonarr/system.go @@ -11,6 +11,7 @@ import ( "time" "golift.io/starr" + "golift.io/starr/starrshared" ) const bpSystem = APIver + "/system" @@ -84,21 +85,10 @@ func (s *Sonarr) GetBackupFilesContext(ctx context.Context) ([]*starr.BackupFile } // SystemTask is a scheduled task from /api/v3/system/task. -type SystemTask struct { - ID int `json:"id,omitempty"` - Name string `json:"name,omitempty"` - TaskName string `json:"taskName,omitempty"` - Interval int `json:"interval,omitempty"` - LastExecution time.Time `json:"lastExecution,omitzero"` - LastStartTime time.Time `json:"lastStartTime,omitzero"` - NextExecution time.Time `json:"nextExecution,omitzero"` - LastDuration string `json:"lastDuration,omitempty"` -} +type SystemTask = starrshared.SystemTask // BackupRestoreResponse is returned when restoring a backup. -type BackupRestoreResponse struct { - RestartRequired bool `json:"restartRequired"` -} +type BackupRestoreResponse = starrshared.BackupRestoreResponse // DeleteBackup deletes a backup file by ID. func (s *Sonarr) DeleteBackup(id int64) error { diff --git a/sonarr/update.go b/sonarr/update.go index 726c6c41..d5bceaa8 100644 --- a/sonarr/update.go +++ b/sonarr/update.go @@ -3,34 +3,18 @@ package sonarr import ( "context" "fmt" - "time" "golift.io/starr" + "golift.io/starr/starrshared" ) const bpUpdate = APIver + "/update" // UpdateChanges is the change log embedded in Update. -type UpdateChanges struct { - New []string `json:"new,omitempty"` - Fixed []string `json:"fixed,omitempty"` -} +type UpdateChanges = starrshared.UpdateChanges // Update is one available or installed update from /api/v3/update. -type Update struct { - ID int `json:"id,omitempty"` - Version string `json:"version,omitempty"` - Branch string `json:"branch,omitempty"` - ReleaseDate time.Time `json:"releaseDate,omitzero"` - FileName string `json:"fileName,omitempty"` - URL string `json:"url,omitempty"` - Installed bool `json:"installed"` - InstalledOn time.Time `json:"installedOn,omitzero"` - Installable bool `json:"installable"` - Latest bool `json:"latest"` - Changes *UpdateChanges `json:"changes,omitempty"` - Hash string `json:"hash,omitempty"` -} +type Update = starrshared.Update // GetUpdates returns available application updates. func (s *Sonarr) GetUpdates() ([]*Update, error) { diff --git a/specs/prowlarr.v1.04.12.2026.json b/specs/prowlarr.v1.04.12.2026.json new file mode 100644 index 00000000..134d31d7 --- /dev/null +++ b/specs/prowlarr.v1.04.12.2026.json @@ -0,0 +1,6356 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "Prowlarr", + "description": "Prowlarr API docs", + "license": { + "name": "GPL-3.0", + "url": "https://github.com/Prowlarr/Prowlarr/blob/develop/LICENSE" + }, + "version": "1.0.0" + }, + "servers": [ + { + "url": "{protocol}://{hostpath}", + "variables": { + "protocol": { + "default": "http", + "enum": [ + "http", + "https" + ] + }, + "hostpath": { + "default": "localhost:9696" + } + } + } + ], + "paths": { + "/api": { + "get": { + "tags": [ + "ApiInfo" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiInfoResource" + } + } + } + } + } + } + }, + "/api/v1/applications/{id}": { + "get": { + "tags": [ + "Application" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApplicationResource" + } + } + } + } + } + }, + "put": { + "tags": [ + "Application" + ], + "parameters": [ + { + "name": "forceSave", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApplicationResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApplicationResource" + } + } + } + } + } + }, + "delete": { + "tags": [ + "Application" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/applications": { + "get": { + "tags": [ + "Application" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ApplicationResource" + } + } + } + } + } + } + }, + "post": { + "tags": [ + "Application" + ], + "parameters": [ + { + "name": "forceSave", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApplicationResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApplicationResource" + } + } + } + } + } + } + }, + "/api/v1/applications/bulk": { + "put": { + "tags": [ + "Application" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApplicationBulkResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApplicationResource" + } + } + } + } + } + }, + "delete": { + "tags": [ + "Application" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApplicationBulkResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/applications/schema": { + "get": { + "tags": [ + "Application" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ApplicationResource" + } + } + } + } + } + } + } + }, + "/api/v1/applications/test": { + "post": { + "tags": [ + "Application" + ], + "parameters": [ + { + "name": "forceTest", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApplicationResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/applications/testall": { + "post": { + "tags": [ + "Application" + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/applications/action/{name}": { + "post": { + "tags": [ + "Application" + ], + "parameters": [ + { + "name": "name", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApplicationResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/appprofile": { + "post": { + "tags": [ + "AppProfile" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AppProfileResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AppProfileResource" + } + } + } + } + } + }, + "get": { + "tags": [ + "AppProfile" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AppProfileResource" + } + } + } + } + } + } + } + }, + "/api/v1/appprofile/{id}": { + "delete": { + "tags": [ + "AppProfile" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + }, + "put": { + "tags": [ + "AppProfile" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AppProfileResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AppProfileResource" + } + } + } + } + } + }, + "get": { + "tags": [ + "AppProfile" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AppProfileResource" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + } + }, + "500": { + "description": "Internal Server Error" + } + } + } + }, + "/api/v1/appprofile/schema": { + "get": { + "tags": [ + "AppProfile" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AppProfileResource" + } + } + } + } + } + } + }, + "/login": { + "post": { + "tags": [ + "Authentication" + ], + "parameters": [ + { + "name": "returnUrl", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "type": "object", + "properties": { + "username": { + "type": "string" + }, + "password": { + "type": "string" + }, + "rememberMe": { + "type": "string" + } + } + }, + "encoding": { + "username": { + "style": "form" + }, + "password": { + "style": "form" + }, + "rememberMe": { + "style": "form" + } + } + } + } + }, + "responses": { + "200": { + "description": "OK" + } + } + }, + "get": { + "tags": [ + "StaticResource" + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/logout": { + "get": { + "tags": [ + "Authentication" + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/system/backup": { + "get": { + "tags": [ + "Backup" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BackupResource" + } + } + } + } + } + } + } + }, + "/api/v1/system/backup/{id}": { + "delete": { + "tags": [ + "Backup" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/system/backup/restore/{id}": { + "post": { + "tags": [ + "Backup" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/system/backup/restore/upload": { + "post": { + "tags": [ + "Backup" + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/command/{id}": { + "get": { + "tags": [ + "Command" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CommandResource" + } + } + } + } + } + }, + "delete": { + "tags": [ + "Command" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/command": { + "post": { + "tags": [ + "Command" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CommandResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CommandResource" + } + } + } + } + } + }, + "get": { + "tags": [ + "Command" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CommandResource" + } + } + } + } + } + } + } + }, + "/api/v1/customfilter/{id}": { + "get": { + "tags": [ + "CustomFilter" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CustomFilterResource" + } + } + } + } + } + }, + "put": { + "tags": [ + "CustomFilter" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CustomFilterResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CustomFilterResource" + } + } + } + } + } + }, + "delete": { + "tags": [ + "CustomFilter" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/customfilter": { + "get": { + "tags": [ + "CustomFilter" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CustomFilterResource" + } + } + } + } + } + } + }, + "post": { + "tags": [ + "CustomFilter" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CustomFilterResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CustomFilterResource" + } + } + } + } + } + } + }, + "/api/v1/config/development/{id}": { + "put": { + "tags": [ + "DevelopmentConfig" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DevelopmentConfigResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DevelopmentConfigResource" + } + } + } + } + } + }, + "get": { + "tags": [ + "DevelopmentConfig" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DevelopmentConfigResource" + } + } + } + } + } + } + }, + "/api/v1/config/development": { + "get": { + "tags": [ + "DevelopmentConfig" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DevelopmentConfigResource" + } + } + } + } + } + } + }, + "/api/v1/downloadclient/{id}": { + "get": { + "tags": [ + "DownloadClient" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientResource" + } + } + } + } + } + }, + "put": { + "tags": [ + "DownloadClient" + ], + "parameters": [ + { + "name": "forceSave", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientResource" + } + } + } + } + } + }, + "delete": { + "tags": [ + "DownloadClient" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/downloadclient": { + "get": { + "tags": [ + "DownloadClient" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DownloadClientResource" + } + } + } + } + } + } + }, + "post": { + "tags": [ + "DownloadClient" + ], + "parameters": [ + { + "name": "forceSave", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientResource" + } + } + } + } + } + } + }, + "/api/v1/downloadclient/bulk": { + "put": { + "tags": [ + "DownloadClient" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientBulkResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientResource" + } + } + } + } + } + }, + "delete": { + "tags": [ + "DownloadClient" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientBulkResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/downloadclient/schema": { + "get": { + "tags": [ + "DownloadClient" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DownloadClientResource" + } + } + } + } + } + } + } + }, + "/api/v1/downloadclient/test": { + "post": { + "tags": [ + "DownloadClient" + ], + "parameters": [ + { + "name": "forceTest", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/downloadclient/testall": { + "post": { + "tags": [ + "DownloadClient" + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/downloadclient/action/{name}": { + "post": { + "tags": [ + "DownloadClient" + ], + "parameters": [ + { + "name": "name", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/config/downloadclient/{id}": { + "get": { + "tags": [ + "DownloadClientConfig" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientConfigResource" + } + } + } + } + } + }, + "put": { + "tags": [ + "DownloadClientConfig" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientConfigResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientConfigResource" + } + } + } + } + } + } + }, + "/api/v1/config/downloadclient": { + "get": { + "tags": [ + "DownloadClientConfig" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientConfigResource" + } + } + } + } + } + } + }, + "/api/v1/filesystem": { + "get": { + "tags": [ + "FileSystem" + ], + "parameters": [ + { + "name": "path", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "includeFiles", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "name": "allowFoldersWithoutTrailingSlashes", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/filesystem/type": { + "get": { + "tags": [ + "FileSystem" + ], + "parameters": [ + { + "name": "path", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/health": { + "get": { + "tags": [ + "Health" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/HealthResource" + } + } + } + } + } + } + } + }, + "/api/v1/history": { + "get": { + "tags": [ + "History" + ], + "parameters": [ + { + "name": "page", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 1 + } + }, + { + "name": "pageSize", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 10 + } + }, + { + "name": "sortKey", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "sortDirection", + "in": "query", + "schema": { + "$ref": "#/components/schemas/SortDirection" + } + }, + { + "name": "eventType", + "in": "query", + "schema": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + } + } + }, + { + "name": "successful", + "in": "query", + "schema": { + "type": "boolean" + } + }, + { + "name": "downloadId", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "indexerIds", + "in": "query", + "schema": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + } + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HistoryResourcePagingResource" + } + } + } + } + } + } + }, + "/api/v1/history/since": { + "get": { + "tags": [ + "History" + ], + "parameters": [ + { + "name": "date", + "in": "query", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "eventType", + "in": "query", + "schema": { + "$ref": "#/components/schemas/HistoryEventType" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/HistoryResource" + } + } + } + } + } + } + } + }, + "/api/v1/history/indexer": { + "get": { + "tags": [ + "History" + ], + "parameters": [ + { + "name": "indexerId", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "eventType", + "in": "query", + "schema": { + "$ref": "#/components/schemas/HistoryEventType" + } + }, + { + "name": "limit", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/HistoryResource" + } + } + } + } + } + } + } + }, + "/api/v1/config/host/{id}": { + "get": { + "tags": [ + "HostConfig" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HostConfigResource" + } + } + } + } + } + }, + "put": { + "tags": [ + "HostConfig" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HostConfigResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HostConfigResource" + } + } + } + } + } + } + }, + "/api/v1/config/host": { + "get": { + "tags": [ + "HostConfig" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HostConfigResource" + } + } + } + } + } + } + }, + "/api/v1/indexer/{id}": { + "get": { + "tags": [ + "Indexer" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerResource" + } + } + } + } + } + }, + "put": { + "tags": [ + "Indexer" + ], + "parameters": [ + { + "name": "forceSave", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerResource" + } + } + } + } + } + }, + "delete": { + "tags": [ + "Indexer" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/indexer": { + "get": { + "tags": [ + "Indexer" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IndexerResource" + } + } + } + } + } + } + }, + "post": { + "tags": [ + "Indexer" + ], + "parameters": [ + { + "name": "forceSave", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerResource" + } + } + } + } + } + } + }, + "/api/v1/indexer/bulk": { + "put": { + "tags": [ + "Indexer" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerBulkResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerResource" + } + } + } + } + } + }, + "delete": { + "tags": [ + "Indexer" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerBulkResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/indexer/schema": { + "get": { + "tags": [ + "Indexer" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IndexerResource" + } + } + } + } + } + } + } + }, + "/api/v1/indexer/test": { + "post": { + "tags": [ + "Indexer" + ], + "parameters": [ + { + "name": "forceTest", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/indexer/testall": { + "post": { + "tags": [ + "Indexer" + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/indexer/action/{name}": { + "post": { + "tags": [ + "Indexer" + ], + "parameters": [ + { + "name": "name", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/indexer/categories": { + "get": { + "tags": [ + "IndexerDefaultCategories" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IndexerCategory" + } + } + } + } + } + } + } + }, + "/api/v1/indexerproxy/{id}": { + "get": { + "tags": [ + "IndexerProxy" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerProxyResource" + } + } + } + } + } + }, + "put": { + "tags": [ + "IndexerProxy" + ], + "parameters": [ + { + "name": "forceSave", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerProxyResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerProxyResource" + } + } + } + } + } + }, + "delete": { + "tags": [ + "IndexerProxy" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/indexerproxy": { + "get": { + "tags": [ + "IndexerProxy" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IndexerProxyResource" + } + } + } + } + } + } + }, + "post": { + "tags": [ + "IndexerProxy" + ], + "parameters": [ + { + "name": "forceSave", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerProxyResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerProxyResource" + } + } + } + } + } + } + }, + "/api/v1/indexerproxy/schema": { + "get": { + "tags": [ + "IndexerProxy" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IndexerProxyResource" + } + } + } + } + } + } + } + }, + "/api/v1/indexerproxy/test": { + "post": { + "tags": [ + "IndexerProxy" + ], + "parameters": [ + { + "name": "forceTest", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerProxyResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/indexerproxy/testall": { + "post": { + "tags": [ + "IndexerProxy" + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/indexerproxy/action/{name}": { + "post": { + "tags": [ + "IndexerProxy" + ], + "parameters": [ + { + "name": "name", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerProxyResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/indexerstats": { + "get": { + "tags": [ + "IndexerStats" + ], + "parameters": [ + { + "name": "startDate", + "in": "query", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "endDate", + "in": "query", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "indexers", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "protocols", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "tags", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerStatsResource" + } + } + } + } + } + } + }, + "/api/v1/indexerstatus": { + "get": { + "tags": [ + "IndexerStatus" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IndexerStatusResource" + } + } + } + } + } + } + } + }, + "/api/v1/localization": { + "get": { + "tags": [ + "Localization" + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/localization/options": { + "get": { + "tags": [ + "Localization" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LocalizationOption" + } + } + } + } + } + } + } + }, + "/api/v1/log": { + "get": { + "tags": [ + "Log" + ], + "parameters": [ + { + "name": "page", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 1 + } + }, + { + "name": "pageSize", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 10 + } + }, + { + "name": "sortKey", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "sortDirection", + "in": "query", + "schema": { + "$ref": "#/components/schemas/SortDirection" + } + }, + { + "name": "level", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LogResourcePagingResource" + } + } + } + } + } + } + }, + "/api/v1/log/file": { + "get": { + "tags": [ + "LogFile" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LogFileResource" + } + } + } + } + } + } + } + }, + "/api/v1/log/file/{filename}": { + "get": { + "tags": [ + "LogFile" + ], + "parameters": [ + { + "name": "filename", + "in": "path", + "required": true, + "schema": { + "pattern": "[-.a-zA-Z0-9]+?\\.txt", + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/IActionResult" + } + } + } + } + } + } + }, + "/api/v1/indexer/{id}/newznab": { + "get": { + "tags": [ + "Newznab" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "t", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "q", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "cat", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "imdbid", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "tmdbid", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "extended", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "limit", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "offset", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "minage", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxage", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "minsize", + "in": "query", + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "maxsize", + "in": "query", + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "rid", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "tvmazeid", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "traktid", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "tvdbid", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "doubanid", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "season", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "ep", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "album", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "artist", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "label", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "track", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "year", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "genre", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "author", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "title", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "publisher", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "configured", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "source", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "host", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "server", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/{id}/api": { + "get": { + "tags": [ + "Newznab" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "t", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "q", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "cat", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "imdbid", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "tmdbid", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "extended", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "limit", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "offset", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "minage", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxage", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "minsize", + "in": "query", + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "maxsize", + "in": "query", + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "rid", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "tvmazeid", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "traktid", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "tvdbid", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "doubanid", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "season", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "ep", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "album", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "artist", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "label", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "track", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "year", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "genre", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "author", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "title", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "publisher", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "configured", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "source", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "host", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "server", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/indexer/{id}/download": { + "get": { + "tags": [ + "Newznab" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "link", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "file", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/{id}/download": { + "get": { + "tags": [ + "Newznab" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "link", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "file", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/notification/{id}": { + "get": { + "tags": [ + "Notification" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationResource" + } + } + } + } + } + }, + "put": { + "tags": [ + "Notification" + ], + "parameters": [ + { + "name": "forceSave", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationResource" + } + } + } + } + } + }, + "delete": { + "tags": [ + "Notification" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/notification": { + "get": { + "tags": [ + "Notification" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/NotificationResource" + } + } + } + } + } + } + }, + "post": { + "tags": [ + "Notification" + ], + "parameters": [ + { + "name": "forceSave", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationResource" + } + } + } + } + } + } + }, + "/api/v1/notification/schema": { + "get": { + "tags": [ + "Notification" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/NotificationResource" + } + } + } + } + } + } + } + }, + "/api/v1/notification/test": { + "post": { + "tags": [ + "Notification" + ], + "parameters": [ + { + "name": "forceTest", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/notification/testall": { + "post": { + "tags": [ + "Notification" + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/notification/action/{name}": { + "post": { + "tags": [ + "Notification" + ], + "parameters": [ + { + "name": "name", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/ping": { + "get": { + "tags": [ + "Ping" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PingResource" + } + } + } + } + } + }, + "head": { + "tags": [ + "Ping" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PingResource" + } + } + } + } + } + } + }, + "/api/v1/search": { + "post": { + "tags": [ + "Search" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ReleaseResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ReleaseResource" + } + } + } + } + } + }, + "get": { + "tags": [ + "Search" + ], + "parameters": [ + { + "name": "query", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "type", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "indexerIds", + "in": "query", + "schema": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + } + } + }, + { + "name": "categories", + "in": "query", + "schema": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + } + } + }, + { + "name": "limit", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "offset", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ReleaseResource" + } + } + } + } + } + } + } + }, + "/api/v1/search/bulk": { + "post": { + "tags": [ + "Search" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ReleaseResource" + } + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ReleaseResource" + } + } + } + } + } + } + }, + "/content/{path}": { + "get": { + "tags": [ + "StaticResource" + ], + "parameters": [ + { + "name": "path", + "in": "path", + "required": true, + "schema": { + "pattern": "^(?!api/).*", + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/": { + "get": { + "tags": [ + "StaticResource" + ], + "parameters": [ + { + "name": "path", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/{path}": { + "get": { + "tags": [ + "StaticResource" + ], + "parameters": [ + { + "name": "path", + "in": "path", + "required": true, + "schema": { + "pattern": "^(?!api/).*", + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/system/status": { + "get": { + "tags": [ + "System" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SystemResource" + } + } + } + } + } + } + }, + "/api/v1/system/routes": { + "get": { + "tags": [ + "System" + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/system/routes/duplicate": { + "get": { + "tags": [ + "System" + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/system/shutdown": { + "post": { + "tags": [ + "System" + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/system/restart": { + "post": { + "tags": [ + "System" + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/tag/{id}": { + "get": { + "tags": [ + "Tag" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagResource" + } + } + } + } + } + }, + "put": { + "tags": [ + "Tag" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagResource" + } + } + } + } + } + }, + "delete": { + "tags": [ + "Tag" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/tag": { + "get": { + "tags": [ + "Tag" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TagResource" + } + } + } + } + } + } + }, + "post": { + "tags": [ + "Tag" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagResource" + } + } + } + } + } + } + }, + "/api/v1/tag/detail/{id}": { + "get": { + "tags": [ + "TagDetails" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagDetailsResource" + } + } + } + } + } + } + }, + "/api/v1/tag/detail": { + "get": { + "tags": [ + "TagDetails" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TagDetailsResource" + } + } + } + } + } + } + } + }, + "/api/v1/system/task": { + "get": { + "tags": [ + "Task" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TaskResource" + } + } + } + } + } + } + } + }, + "/api/v1/system/task/{id}": { + "get": { + "tags": [ + "Task" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TaskResource" + } + } + } + } + } + } + }, + "/api/v1/config/ui/{id}": { + "put": { + "tags": [ + "UiConfig" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UiConfigResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UiConfigResource" + } + } + } + } + } + }, + "get": { + "tags": [ + "UiConfig" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UiConfigResource" + } + } + } + } + } + } + }, + "/api/v1/config/ui": { + "get": { + "tags": [ + "UiConfig" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UiConfigResource" + } + } + } + } + } + } + }, + "/api/v1/update": { + "get": { + "tags": [ + "Update" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/UpdateResource" + } + } + } + } + } + } + } + }, + "/api/v1/log/file/update": { + "get": { + "tags": [ + "UpdateLogFile" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LogFileResource" + } + } + } + } + } + } + } + }, + "/api/v1/log/file/update/{filename}": { + "get": { + "tags": [ + "UpdateLogFile" + ], + "parameters": [ + { + "name": "filename", + "in": "path", + "required": true, + "schema": { + "pattern": "[-.a-zA-Z0-9]+?\\.txt", + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/IActionResult" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "ApiInfoResource": { + "type": "object", + "properties": { + "current": { + "type": "string", + "nullable": true + }, + "deprecated": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "AppProfileResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string", + "nullable": true + }, + "enableRss": { + "type": "boolean" + }, + "enableAutomaticSearch": { + "type": "boolean" + }, + "enableInteractiveSearch": { + "type": "boolean" + }, + "minimumSeeders": { + "type": "integer", + "format": "int32" + } + }, + "additionalProperties": false + }, + "ApplicationBulkResource": { + "type": "object", + "properties": { + "ids": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + }, + "tags": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + }, + "applyTags": { + "$ref": "#/components/schemas/ApplyTags" + }, + "syncLevel": { + "$ref": "#/components/schemas/ApplicationSyncLevel" + } + }, + "additionalProperties": false + }, + "ApplicationResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string", + "nullable": true + }, + "fields": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Field" + }, + "nullable": true + }, + "implementationName": { + "type": "string", + "nullable": true + }, + "implementation": { + "type": "string", + "nullable": true + }, + "configContract": { + "type": "string", + "nullable": true + }, + "infoLink": { + "type": "string", + "nullable": true + }, + "message": { + "$ref": "#/components/schemas/ProviderMessage" + }, + "tags": { + "uniqueItems": true, + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + }, + "presets": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ApplicationResource" + }, + "nullable": true + }, + "syncLevel": { + "$ref": "#/components/schemas/ApplicationSyncLevel" + }, + "testCommand": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "ApplicationSyncLevel": { + "enum": [ + "disabled", + "addOnly", + "fullSync" + ], + "type": "string" + }, + "ApplyTags": { + "enum": [ + "add", + "remove", + "replace" + ], + "type": "string" + }, + "AuthenticationRequiredType": { + "enum": [ + "enabled", + "disabledForLocalAddresses" + ], + "type": "string" + }, + "AuthenticationType": { + "enum": [ + "none", + "basic", + "forms", + "external" + ], + "type": "string" + }, + "BackupResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string", + "nullable": true + }, + "path": { + "type": "string", + "nullable": true + }, + "type": { + "$ref": "#/components/schemas/BackupType" + }, + "size": { + "type": "integer", + "format": "int64" + }, + "time": { + "type": "string", + "format": "date-time" + } + }, + "additionalProperties": false + }, + "BackupType": { + "enum": [ + "scheduled", + "manual", + "update" + ], + "type": "string" + }, + "BookSearchParam": { + "enum": [ + "q", + "title", + "author", + "publisher", + "genre", + "year" + ], + "type": "string" + }, + "CertificateValidationType": { + "enum": [ + "enabled", + "disabledForLocalAddresses", + "disabled" + ], + "type": "string" + }, + "Command": { + "type": "object", + "properties": { + "sendUpdatesToClient": { + "type": "boolean" + }, + "updateScheduledTask": { + "type": "boolean", + "readOnly": true + }, + "completionMessage": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "requiresDiskAccess": { + "type": "boolean", + "readOnly": true + }, + "isExclusive": { + "type": "boolean", + "readOnly": true + }, + "isTypeExclusive": { + "type": "boolean", + "readOnly": true + }, + "name": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "lastExecutionTime": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "lastStartTime": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "trigger": { + "$ref": "#/components/schemas/CommandTrigger" + }, + "suppressMessages": { + "type": "boolean" + }, + "clientUserAgent": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "CommandPriority": { + "enum": [ + "normal", + "high", + "low" + ], + "type": "string" + }, + "CommandResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string", + "nullable": true + }, + "commandName": { + "type": "string", + "nullable": true + }, + "message": { + "type": "string", + "nullable": true + }, + "body": { + "$ref": "#/components/schemas/Command" + }, + "priority": { + "$ref": "#/components/schemas/CommandPriority" + }, + "status": { + "$ref": "#/components/schemas/CommandStatus" + }, + "queued": { + "type": "string", + "format": "date-time" + }, + "started": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "ended": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "duration": { + "type": "string", + "format": "date-span", + "nullable": true + }, + "exception": { + "type": "string", + "nullable": true + }, + "trigger": { + "$ref": "#/components/schemas/CommandTrigger" + }, + "clientUserAgent": { + "type": "string", + "nullable": true + }, + "stateChangeTime": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "sendUpdatesToClient": { + "type": "boolean" + }, + "updateScheduledTask": { + "type": "boolean" + }, + "lastExecutionTime": { + "type": "string", + "format": "date-time", + "nullable": true + } + }, + "additionalProperties": false + }, + "CommandStatus": { + "enum": [ + "queued", + "started", + "completed", + "failed", + "aborted", + "cancelled", + "orphaned" + ], + "type": "string" + }, + "CommandTrigger": { + "enum": [ + "unspecified", + "manual", + "scheduled" + ], + "type": "string" + }, + "CustomFilterResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "type": { + "type": "string", + "nullable": true + }, + "label": { + "type": "string", + "nullable": true + }, + "filters": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": { } + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "DatabaseType": { + "enum": [ + "sqLite", + "postgreSQL" + ], + "type": "string" + }, + "DevelopmentConfigResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "consoleLogLevel": { + "type": "string", + "nullable": true + }, + "logSql": { + "type": "boolean" + }, + "logIndexerResponse": { + "type": "boolean" + }, + "logRotate": { + "type": "integer", + "format": "int32" + }, + "filterSentryEvents": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "DownloadClientBulkResource": { + "type": "object", + "properties": { + "ids": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + }, + "tags": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + }, + "applyTags": { + "$ref": "#/components/schemas/ApplyTags" + }, + "enable": { + "type": "boolean", + "nullable": true + }, + "priority": { + "type": "integer", + "format": "int32", + "nullable": true + } + }, + "additionalProperties": false + }, + "DownloadClientCategory": { + "type": "object", + "properties": { + "clientCategory": { + "type": "string", + "nullable": true + }, + "categories": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "DownloadClientConfigResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + } + }, + "additionalProperties": false + }, + "DownloadClientResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string", + "nullable": true + }, + "fields": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Field" + }, + "nullable": true + }, + "implementationName": { + "type": "string", + "nullable": true + }, + "implementation": { + "type": "string", + "nullable": true + }, + "configContract": { + "type": "string", + "nullable": true + }, + "infoLink": { + "type": "string", + "nullable": true + }, + "message": { + "$ref": "#/components/schemas/ProviderMessage" + }, + "tags": { + "uniqueItems": true, + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + }, + "presets": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DownloadClientResource" + }, + "nullable": true + }, + "enable": { + "type": "boolean" + }, + "protocol": { + "$ref": "#/components/schemas/DownloadProtocol" + }, + "priority": { + "type": "integer", + "format": "int32" + }, + "categories": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DownloadClientCategory" + }, + "nullable": true + }, + "supportsCategories": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "DownloadProtocol": { + "enum": [ + "unknown", + "usenet", + "torrent" + ], + "type": "string" + }, + "Field": { + "type": "object", + "properties": { + "order": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string", + "nullable": true + }, + "label": { + "type": "string", + "nullable": true + }, + "unit": { + "type": "string", + "nullable": true + }, + "helpText": { + "type": "string", + "nullable": true + }, + "helpTextWarning": { + "type": "string", + "nullable": true + }, + "helpLink": { + "type": "string", + "nullable": true + }, + "value": { + "nullable": true + }, + "type": { + "type": "string", + "nullable": true + }, + "advanced": { + "type": "boolean" + }, + "selectOptions": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SelectOption" + }, + "nullable": true + }, + "selectOptionsProviderAction": { + "type": "string", + "nullable": true + }, + "section": { + "type": "string", + "nullable": true + }, + "hidden": { + "type": "string", + "nullable": true + }, + "privacy": { + "$ref": "#/components/schemas/PrivacyLevel" + }, + "placeholder": { + "type": "string", + "nullable": true + }, + "isFloat": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "HealthCheckResult": { + "enum": [ + "ok", + "notice", + "warning", + "error" + ], + "type": "string" + }, + "HealthResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "source": { + "type": "string", + "nullable": true + }, + "type": { + "$ref": "#/components/schemas/HealthCheckResult" + }, + "message": { + "type": "string", + "nullable": true + }, + "wikiUrl": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "HistoryEventType": { + "enum": [ + "unknown", + "releaseGrabbed", + "indexerQuery", + "indexerRss", + "indexerAuth", + "indexerInfo" + ], + "type": "string" + }, + "HistoryResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "indexerId": { + "type": "integer", + "format": "int32" + }, + "date": { + "type": "string", + "format": "date-time" + }, + "downloadId": { + "type": "string", + "nullable": true + }, + "successful": { + "type": "boolean" + }, + "eventType": { + "$ref": "#/components/schemas/HistoryEventType" + }, + "data": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "HistoryResourcePagingResource": { + "type": "object", + "properties": { + "page": { + "type": "integer", + "format": "int32" + }, + "pageSize": { + "type": "integer", + "format": "int32" + }, + "sortKey": { + "type": "string", + "nullable": true + }, + "sortDirection": { + "$ref": "#/components/schemas/SortDirection" + }, + "totalRecords": { + "type": "integer", + "format": "int32" + }, + "records": { + "type": "array", + "items": { + "$ref": "#/components/schemas/HistoryResource" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "HostConfigResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "bindAddress": { + "type": "string", + "nullable": true + }, + "port": { + "type": "integer", + "format": "int32" + }, + "sslPort": { + "type": "integer", + "format": "int32" + }, + "enableSsl": { + "type": "boolean" + }, + "launchBrowser": { + "type": "boolean" + }, + "authenticationMethod": { + "$ref": "#/components/schemas/AuthenticationType" + }, + "authenticationRequired": { + "$ref": "#/components/schemas/AuthenticationRequiredType" + }, + "analyticsEnabled": { + "type": "boolean" + }, + "username": { + "type": "string", + "nullable": true + }, + "password": { + "type": "string", + "nullable": true + }, + "passwordConfirmation": { + "type": "string", + "nullable": true + }, + "logLevel": { + "type": "string", + "nullable": true + }, + "logSizeLimit": { + "type": "integer", + "format": "int32" + }, + "consoleLogLevel": { + "type": "string", + "nullable": true + }, + "branch": { + "type": "string", + "nullable": true + }, + "apiKey": { + "type": "string", + "nullable": true + }, + "sslCertPath": { + "type": "string", + "nullable": true + }, + "sslCertPassword": { + "type": "string", + "nullable": true + }, + "urlBase": { + "type": "string", + "nullable": true + }, + "instanceName": { + "type": "string", + "nullable": true + }, + "applicationUrl": { + "type": "string", + "nullable": true + }, + "updateAutomatically": { + "type": "boolean" + }, + "updateMechanism": { + "$ref": "#/components/schemas/UpdateMechanism" + }, + "updateScriptPath": { + "type": "string", + "nullable": true + }, + "proxyEnabled": { + "type": "boolean" + }, + "proxyType": { + "$ref": "#/components/schemas/ProxyType" + }, + "proxyHostname": { + "type": "string", + "nullable": true + }, + "proxyPort": { + "type": "integer", + "format": "int32" + }, + "proxyUsername": { + "type": "string", + "nullable": true + }, + "proxyPassword": { + "type": "string", + "nullable": true + }, + "proxyBypassFilter": { + "type": "string", + "nullable": true + }, + "proxyBypassLocalAddresses": { + "type": "boolean" + }, + "certificateValidation": { + "$ref": "#/components/schemas/CertificateValidationType" + }, + "backupFolder": { + "type": "string", + "nullable": true + }, + "backupInterval": { + "type": "integer", + "format": "int32" + }, + "backupRetention": { + "type": "integer", + "format": "int32" + }, + "historyCleanupDays": { + "type": "integer", + "format": "int32" + }, + "trustCgnatIpAddresses": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "HostStatistics": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true + }, + "numberOfQueries": { + "type": "integer", + "format": "int32" + }, + "numberOfGrabs": { + "type": "integer", + "format": "int32" + } + }, + "additionalProperties": false + }, + "IActionResult": { + "type": "object", + "additionalProperties": false + }, + "IndexerBulkResource": { + "type": "object", + "properties": { + "ids": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + }, + "tags": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + }, + "applyTags": { + "$ref": "#/components/schemas/ApplyTags" + }, + "enable": { + "type": "boolean", + "nullable": true + }, + "appProfileId": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "priority": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "minimumSeeders": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "seedRatio": { + "type": "number", + "format": "double", + "nullable": true + }, + "seedTime": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "packSeedTime": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "preferMagnetUrl": { + "type": "boolean", + "nullable": true + } + }, + "additionalProperties": false + }, + "IndexerCapabilityResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "limitsMax": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "limitsDefault": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "categories": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IndexerCategory" + }, + "nullable": true + }, + "supportsRawSearch": { + "type": "boolean" + }, + "searchParams": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SearchParam" + }, + "nullable": true + }, + "tvSearchParams": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TvSearchParam" + }, + "nullable": true + }, + "movieSearchParams": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MovieSearchParam" + }, + "nullable": true + }, + "musicSearchParams": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MusicSearchParam" + }, + "nullable": true + }, + "bookSearchParams": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BookSearchParam" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "IndexerCategory": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string", + "nullable": true + }, + "description": { + "type": "string", + "nullable": true + }, + "subCategories": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IndexerCategory" + }, + "nullable": true, + "readOnly": true + } + }, + "additionalProperties": false + }, + "IndexerPrivacy": { + "enum": [ + "public", + "semiPrivate", + "private" + ], + "type": "string" + }, + "IndexerProxyResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string", + "nullable": true + }, + "fields": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Field" + }, + "nullable": true + }, + "implementationName": { + "type": "string", + "nullable": true + }, + "implementation": { + "type": "string", + "nullable": true + }, + "configContract": { + "type": "string", + "nullable": true + }, + "infoLink": { + "type": "string", + "nullable": true + }, + "message": { + "$ref": "#/components/schemas/ProviderMessage" + }, + "tags": { + "uniqueItems": true, + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + }, + "presets": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IndexerProxyResource" + }, + "nullable": true + }, + "link": { + "type": "string", + "nullable": true + }, + "onHealthIssue": { + "type": "boolean" + }, + "supportsOnHealthIssue": { + "type": "boolean" + }, + "includeHealthWarnings": { + "type": "boolean" + }, + "testCommand": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "IndexerResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string", + "nullable": true + }, + "fields": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Field" + }, + "nullable": true + }, + "implementationName": { + "type": "string", + "nullable": true + }, + "implementation": { + "type": "string", + "nullable": true + }, + "configContract": { + "type": "string", + "nullable": true + }, + "infoLink": { + "type": "string", + "nullable": true + }, + "message": { + "$ref": "#/components/schemas/ProviderMessage" + }, + "tags": { + "uniqueItems": true, + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + }, + "presets": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IndexerResource" + }, + "nullable": true + }, + "indexerUrls": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "legacyUrls": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "definitionName": { + "type": "string", + "nullable": true + }, + "description": { + "type": "string", + "nullable": true + }, + "language": { + "type": "string", + "nullable": true + }, + "encoding": { + "type": "string", + "nullable": true + }, + "enable": { + "type": "boolean" + }, + "redirect": { + "type": "boolean" + }, + "supportsRss": { + "type": "boolean" + }, + "supportsSearch": { + "type": "boolean" + }, + "supportsRedirect": { + "type": "boolean" + }, + "supportsPagination": { + "type": "boolean" + }, + "appProfileId": { + "type": "integer", + "format": "int32" + }, + "protocol": { + "$ref": "#/components/schemas/DownloadProtocol" + }, + "privacy": { + "$ref": "#/components/schemas/IndexerPrivacy" + }, + "capabilities": { + "$ref": "#/components/schemas/IndexerCapabilityResource" + }, + "priority": { + "type": "integer", + "format": "int32" + }, + "downloadClientId": { + "type": "integer", + "format": "int32" + }, + "added": { + "type": "string", + "format": "date-time" + }, + "status": { + "$ref": "#/components/schemas/IndexerStatusResource" + }, + "sortName": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "IndexerStatistics": { + "type": "object", + "properties": { + "indexerId": { + "type": "integer", + "format": "int32" + }, + "indexerName": { + "type": "string", + "nullable": true + }, + "averageResponseTime": { + "type": "integer", + "format": "int32" + }, + "averageGrabResponseTime": { + "type": "integer", + "format": "int32" + }, + "numberOfQueries": { + "type": "integer", + "format": "int32" + }, + "numberOfGrabs": { + "type": "integer", + "format": "int32" + }, + "numberOfRssQueries": { + "type": "integer", + "format": "int32" + }, + "numberOfAuthQueries": { + "type": "integer", + "format": "int32" + }, + "numberOfFailedQueries": { + "type": "integer", + "format": "int32" + }, + "numberOfFailedGrabs": { + "type": "integer", + "format": "int32" + }, + "numberOfFailedRssQueries": { + "type": "integer", + "format": "int32" + }, + "numberOfFailedAuthQueries": { + "type": "integer", + "format": "int32" + } + }, + "additionalProperties": false + }, + "IndexerStatsResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "indexers": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IndexerStatistics" + }, + "nullable": true + }, + "userAgents": { + "type": "array", + "items": { + "$ref": "#/components/schemas/UserAgentStatistics" + }, + "nullable": true + }, + "hosts": { + "type": "array", + "items": { + "$ref": "#/components/schemas/HostStatistics" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "IndexerStatusResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "indexerId": { + "type": "integer", + "format": "int32" + }, + "disabledTill": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "mostRecentFailure": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "initialFailure": { + "type": "string", + "format": "date-time", + "nullable": true + } + }, + "additionalProperties": false + }, + "LocalizationOption": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true + }, + "value": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "LogFileResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "filename": { + "type": "string", + "nullable": true + }, + "lastWriteTime": { + "type": "string", + "format": "date-time" + }, + "contentsUrl": { + "type": "string", + "nullable": true + }, + "downloadUrl": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "LogResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "time": { + "type": "string", + "format": "date-time" + }, + "exception": { + "type": "string", + "nullable": true + }, + "exceptionType": { + "type": "string", + "nullable": true + }, + "level": { + "type": "string", + "nullable": true + }, + "logger": { + "type": "string", + "nullable": true + }, + "message": { + "type": "string", + "nullable": true + }, + "method": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "LogResourcePagingResource": { + "type": "object", + "properties": { + "page": { + "type": "integer", + "format": "int32" + }, + "pageSize": { + "type": "integer", + "format": "int32" + }, + "sortKey": { + "type": "string", + "nullable": true + }, + "sortDirection": { + "$ref": "#/components/schemas/SortDirection" + }, + "totalRecords": { + "type": "integer", + "format": "int32" + }, + "records": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LogResource" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "MovieSearchParam": { + "enum": [ + "q", + "imdbId", + "tmdbId", + "imdbTitle", + "imdbYear", + "traktId", + "genre", + "doubanId", + "year" + ], + "type": "string" + }, + "MusicSearchParam": { + "enum": [ + "q", + "album", + "artist", + "label", + "year", + "genre", + "track" + ], + "type": "string" + }, + "NotificationResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string", + "nullable": true + }, + "fields": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Field" + }, + "nullable": true + }, + "implementationName": { + "type": "string", + "nullable": true + }, + "implementation": { + "type": "string", + "nullable": true + }, + "configContract": { + "type": "string", + "nullable": true + }, + "infoLink": { + "type": "string", + "nullable": true + }, + "message": { + "$ref": "#/components/schemas/ProviderMessage" + }, + "tags": { + "uniqueItems": true, + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + }, + "presets": { + "type": "array", + "items": { + "$ref": "#/components/schemas/NotificationResource" + }, + "nullable": true + }, + "link": { + "type": "string", + "nullable": true + }, + "onGrab": { + "type": "boolean" + }, + "onHealthIssue": { + "type": "boolean" + }, + "onHealthRestored": { + "type": "boolean" + }, + "onApplicationUpdate": { + "type": "boolean" + }, + "supportsOnGrab": { + "type": "boolean" + }, + "includeManualGrabs": { + "type": "boolean" + }, + "supportsOnHealthIssue": { + "type": "boolean" + }, + "supportsOnHealthRestored": { + "type": "boolean" + }, + "includeHealthWarnings": { + "type": "boolean" + }, + "supportsOnApplicationUpdate": { + "type": "boolean" + }, + "testCommand": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "PingResource": { + "type": "object", + "properties": { + "status": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "PrivacyLevel": { + "enum": [ + "normal", + "password", + "apiKey", + "userName" + ], + "type": "string" + }, + "ProviderMessage": { + "type": "object", + "properties": { + "message": { + "type": "string", + "nullable": true + }, + "type": { + "$ref": "#/components/schemas/ProviderMessageType" + } + }, + "additionalProperties": false + }, + "ProviderMessageType": { + "enum": [ + "info", + "warning", + "error" + ], + "type": "string" + }, + "ProxyType": { + "enum": [ + "http", + "socks4", + "socks5" + ], + "type": "string" + }, + "ReleaseResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "guid": { + "type": "string", + "nullable": true + }, + "age": { + "type": "integer", + "format": "int32" + }, + "ageHours": { + "type": "number", + "format": "double" + }, + "ageMinutes": { + "type": "number", + "format": "double" + }, + "size": { + "type": "integer", + "format": "int64" + }, + "files": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "grabs": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "indexerId": { + "type": "integer", + "format": "int32" + }, + "indexer": { + "type": "string", + "nullable": true + }, + "subGroup": { + "type": "string", + "nullable": true + }, + "releaseHash": { + "type": "string", + "nullable": true + }, + "title": { + "type": "string", + "nullable": true + }, + "sortTitle": { + "type": "string", + "nullable": true + }, + "imdbId": { + "type": "integer", + "format": "int32" + }, + "tmdbId": { + "type": "integer", + "format": "int32" + }, + "tvdbId": { + "type": "integer", + "format": "int32" + }, + "tvMazeId": { + "type": "integer", + "format": "int32" + }, + "publishDate": { + "type": "string", + "format": "date-time" + }, + "commentUrl": { + "type": "string", + "nullable": true + }, + "downloadUrl": { + "type": "string", + "nullable": true + }, + "infoUrl": { + "type": "string", + "nullable": true + }, + "posterUrl": { + "type": "string", + "nullable": true + }, + "indexerFlags": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "categories": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IndexerCategory" + }, + "nullable": true + }, + "magnetUrl": { + "type": "string", + "nullable": true + }, + "infoHash": { + "type": "string", + "nullable": true + }, + "seeders": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "leechers": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "protocol": { + "$ref": "#/components/schemas/DownloadProtocol" + }, + "fileName": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "downloadClientId": { + "type": "integer", + "format": "int32", + "nullable": true + } + }, + "additionalProperties": false + }, + "RuntimeMode": { + "enum": [ + "console", + "service", + "tray" + ], + "type": "string" + }, + "SearchParam": { + "enum": [ + "q" + ], + "type": "string" + }, + "SelectOption": { + "type": "object", + "properties": { + "value": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string", + "nullable": true + }, + "order": { + "type": "integer", + "format": "int32" + }, + "hint": { + "type": "string", + "nullable": true + }, + "parentValue": { + "type": "integer", + "format": "int32", + "nullable": true + } + }, + "additionalProperties": false + }, + "SortDirection": { + "enum": [ + "default", + "ascending", + "descending" + ], + "type": "string" + }, + "SystemResource": { + "type": "object", + "properties": { + "appName": { + "type": "string", + "nullable": true + }, + "instanceName": { + "type": "string", + "nullable": true + }, + "version": { + "type": "string", + "nullable": true + }, + "buildTime": { + "type": "string", + "format": "date-time" + }, + "isDebug": { + "type": "boolean" + }, + "isProduction": { + "type": "boolean" + }, + "isAdmin": { + "type": "boolean" + }, + "isUserInteractive": { + "type": "boolean" + }, + "startupPath": { + "type": "string", + "nullable": true + }, + "appData": { + "type": "string", + "nullable": true + }, + "osName": { + "type": "string", + "nullable": true + }, + "osVersion": { + "type": "string", + "nullable": true + }, + "isNetCore": { + "type": "boolean" + }, + "isLinux": { + "type": "boolean" + }, + "isOsx": { + "type": "boolean" + }, + "isWindows": { + "type": "boolean" + }, + "isDocker": { + "type": "boolean" + }, + "mode": { + "$ref": "#/components/schemas/RuntimeMode" + }, + "branch": { + "type": "string", + "nullable": true + }, + "databaseType": { + "$ref": "#/components/schemas/DatabaseType" + }, + "databaseVersion": { + "type": "string", + "nullable": true + }, + "authentication": { + "$ref": "#/components/schemas/AuthenticationType" + }, + "migrationVersion": { + "type": "integer", + "format": "int32" + }, + "urlBase": { + "type": "string", + "nullable": true + }, + "runtimeVersion": { + "type": "string", + "nullable": true + }, + "runtimeName": { + "type": "string", + "nullable": true + }, + "startTime": { + "type": "string", + "format": "date-time" + }, + "packageVersion": { + "type": "string", + "nullable": true + }, + "packageAuthor": { + "type": "string", + "nullable": true + }, + "packageUpdateMechanism": { + "$ref": "#/components/schemas/UpdateMechanism" + }, + "packageUpdateMechanismMessage": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "TagDetailsResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "label": { + "type": "string", + "nullable": true + }, + "notificationIds": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + }, + "indexerIds": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + }, + "indexerProxyIds": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + }, + "applicationIds": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "TagResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "label": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "TaskResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string", + "nullable": true + }, + "taskName": { + "type": "string", + "nullable": true + }, + "interval": { + "type": "integer", + "format": "int32" + }, + "lastExecution": { + "type": "string", + "format": "date-time" + }, + "lastStartTime": { + "type": "string", + "format": "date-time" + }, + "nextExecution": { + "type": "string", + "format": "date-time" + }, + "lastDuration": { + "type": "string", + "format": "date-span", + "readOnly": true + } + }, + "additionalProperties": false + }, + "TvSearchParam": { + "enum": [ + "q", + "season", + "ep", + "imdbId", + "tvdbId", + "rId", + "tvMazeId", + "traktId", + "tmdbId", + "doubanId", + "genre", + "year" + ], + "type": "string" + }, + "UiConfigResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "firstDayOfWeek": { + "type": "integer", + "format": "int32" + }, + "calendarWeekColumnHeader": { + "type": "string", + "nullable": true + }, + "shortDateFormat": { + "type": "string", + "nullable": true + }, + "longDateFormat": { + "type": "string", + "nullable": true + }, + "timeFormat": { + "type": "string", + "nullable": true + }, + "showRelativeDates": { + "type": "boolean" + }, + "enableColorImpairedMode": { + "type": "boolean" + }, + "uiLanguage": { + "type": "string", + "nullable": true + }, + "theme": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "UpdateChanges": { + "type": "object", + "properties": { + "new": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "fixed": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "UpdateMechanism": { + "enum": [ + "builtIn", + "script", + "external", + "apt", + "docker" + ], + "type": "string" + }, + "UpdateResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "version": { + "type": "string", + "nullable": true + }, + "branch": { + "type": "string", + "nullable": true + }, + "releaseDate": { + "type": "string", + "format": "date-time" + }, + "fileName": { + "type": "string", + "nullable": true + }, + "url": { + "type": "string", + "nullable": true + }, + "installed": { + "type": "boolean" + }, + "installedOn": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "installable": { + "type": "boolean" + }, + "latest": { + "type": "boolean" + }, + "changes": { + "$ref": "#/components/schemas/UpdateChanges" + }, + "hash": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "UserAgentStatistics": { + "type": "object", + "properties": { + "userAgent": { + "type": "string", + "nullable": true + }, + "numberOfQueries": { + "type": "integer", + "format": "int32" + }, + "numberOfGrabs": { + "type": "integer", + "format": "int32" + } + }, + "additionalProperties": false + } + }, + "securitySchemes": { + "X-Api-Key": { + "type": "apiKey", + "description": "Apikey passed as header", + "name": "X-Api-Key", + "in": "header" + }, + "apikey": { + "type": "apiKey", + "description": "Apikey passed as query parameter", + "name": "apikey", + "in": "query" + } + } + }, + "security": [ + { + "X-Api-Key": [ ] + }, + { + "apikey": [ ] + } + ] +} \ No newline at end of file diff --git a/specs/readarr.v1.04.12.2026.json b/specs/readarr.v1.04.12.2026.json new file mode 100644 index 00000000..550dc5cc --- /dev/null +++ b/specs/readarr.v1.04.12.2026.json @@ -0,0 +1,13781 @@ +{ + "openapi": "3.0.1", + "info": { + "title": "Readarr", + "description": "Readarr API docs", + "license": { + "name": "GPL-3.0", + "url": "https://github.com/Readarr/Readarr/blob/develop/LICENSE.md" + }, + "version": "1.0.0" + }, + "servers": [ + { + "url": "{protocol}://{hostpath}", + "variables": { + "protocol": { + "default": "http", + "enum": [ + "http", + "https" + ] + }, + "hostpath": { + "default": "localhost:8787" + } + } + } + ], + "paths": { + "/api": { + "get": { + "tags": [ + "ApiInfo" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiInfoResource" + } + } + } + } + } + } + }, + "/login": { + "post": { + "tags": [ + "Authentication" + ], + "parameters": [ + { + "name": "returnUrl", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "type": "object", + "properties": { + "username": { + "type": "string" + }, + "password": { + "type": "string" + }, + "rememberMe": { + "type": "string" + } + } + }, + "encoding": { + "username": { + "style": "form" + }, + "password": { + "style": "form" + }, + "rememberMe": { + "style": "form" + } + } + } + } + }, + "responses": { + "200": { + "description": "OK" + } + } + }, + "get": { + "tags": [ + "StaticResource" + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/logout": { + "get": { + "tags": [ + "Authentication" + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/author": { + "get": { + "tags": [ + "Author" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AuthorResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AuthorResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AuthorResource" + } + } + } + } + } + } + }, + "post": { + "tags": [ + "Author" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthorResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/AuthorResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/AuthorResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/AuthorResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthorResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/AuthorResource" + } + } + } + } + } + } + }, + "/api/v1/author/{id}": { + "put": { + "tags": [ + "Author" + ], + "parameters": [ + { + "name": "moveFiles", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthorResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/AuthorResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/AuthorResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/AuthorResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthorResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/AuthorResource" + } + } + } + } + } + }, + "delete": { + "tags": [ + "Author" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "deleteFiles", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "name": "addImportListExclusion", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + }, + "get": { + "tags": [ + "Author" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthorResource" + } + } + } + } + } + } + }, + "/api/v1/author/editor": { + "put": { + "tags": [ + "AuthorEditor" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthorEditorResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/AuthorEditorResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/AuthorEditorResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK" + } + } + }, + "delete": { + "tags": [ + "AuthorEditor" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthorEditorResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/AuthorEditorResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/AuthorEditorResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/author/lookup": { + "get": { + "tags": [ + "AuthorLookup" + ], + "parameters": [ + { + "name": "term", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/system/backup": { + "get": { + "tags": [ + "Backup" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BackupResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BackupResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BackupResource" + } + } + } + } + } + } + } + }, + "/api/v1/system/backup/{id}": { + "delete": { + "tags": [ + "Backup" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/system/backup/restore/{id}": { + "post": { + "tags": [ + "Backup" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/system/backup/restore/upload": { + "post": { + "tags": [ + "Backup" + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/blocklist": { + "get": { + "tags": [ + "Blocklist" + ], + "parameters": [ + { + "name": "page", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 1 + } + }, + { + "name": "pageSize", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 10 + } + }, + { + "name": "sortKey", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "sortDirection", + "in": "query", + "schema": { + "$ref": "#/components/schemas/SortDirection" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BlocklistResourcePagingResource" + } + } + } + } + } + } + }, + "/api/v1/blocklist/{id}": { + "delete": { + "tags": [ + "Blocklist" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/blocklist/bulk": { + "delete": { + "tags": [ + "Blocklist" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BlocklistBulkResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/BlocklistBulkResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/BlocklistBulkResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/book": { + "get": { + "tags": [ + "Book" + ], + "parameters": [ + { + "name": "authorId", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "bookIds", + "in": "query", + "schema": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + } + } + }, + { + "name": "titleSlug", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "includeAllAuthorBooks", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BookResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BookResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BookResource" + } + } + } + } + } + } + }, + "post": { + "tags": [ + "Book" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BookResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/BookResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/BookResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/BookResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/BookResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/BookResource" + } + } + } + } + } + } + }, + "/api/v1/book/{id}/overview": { + "get": { + "tags": [ + "Book" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/book/{id}": { + "put": { + "tags": [ + "Book" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BookResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/BookResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/BookResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/BookResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/BookResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/BookResource" + } + } + } + } + } + }, + "delete": { + "tags": [ + "Book" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "deleteFiles", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "name": "addImportListExclusion", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + }, + "get": { + "tags": [ + "Book" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BookResource" + } + } + } + } + } + } + }, + "/api/v1/book/monitor": { + "put": { + "tags": [ + "Book" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BooksMonitoredResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/BooksMonitoredResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/BooksMonitoredResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/book/editor": { + "put": { + "tags": [ + "BookEditor" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BookEditorResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/BookEditorResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/BookEditorResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK" + } + } + }, + "delete": { + "tags": [ + "BookEditor" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BookEditorResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/BookEditorResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/BookEditorResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/bookfile": { + "get": { + "tags": [ + "BookFile" + ], + "parameters": [ + { + "name": "authorId", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "bookFileIds", + "in": "query", + "schema": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + } + } + }, + { + "name": "bookId", + "in": "query", + "schema": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + } + } + }, + { + "name": "unmapped", + "in": "query", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BookFileResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BookFileResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BookFileResource" + } + } + } + } + } + } + } + }, + "/api/v1/bookfile/{id}": { + "put": { + "tags": [ + "BookFile" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BookFileResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/BookFileResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/BookFileResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/BookFileResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/BookFileResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/BookFileResource" + } + } + } + } + } + }, + "delete": { + "tags": [ + "BookFile" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + }, + "get": { + "tags": [ + "BookFile" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BookFileResource" + } + } + } + } + } + } + }, + "/api/v1/bookfile/editor": { + "put": { + "tags": [ + "BookFile" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BookFileListResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/BookFileListResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/BookFileListResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/bookfile/bulk": { + "delete": { + "tags": [ + "BookFile" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BookFileListResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/BookFileListResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/BookFileListResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/book/lookup": { + "get": { + "tags": [ + "BookLookup" + ], + "parameters": [ + { + "name": "term", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/bookshelf": { + "post": { + "tags": [ + "Bookshelf" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BookshelfResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/BookshelfResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/BookshelfResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/calendar": { + "get": { + "tags": [ + "Calendar" + ], + "parameters": [ + { + "name": "start", + "in": "query", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "end", + "in": "query", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "unmonitored", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "name": "includeAuthor", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BookResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BookResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BookResource" + } + } + } + } + } + } + } + }, + "/api/v1/calendar/{id}": { + "get": { + "tags": [ + "Calendar" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BookResource" + } + } + } + } + } + } + }, + "/feed/v1/calendar/readarr.ics": { + "get": { + "tags": [ + "CalendarFeed" + ], + "parameters": [ + { + "name": "pastDays", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 7 + } + }, + { + "name": "futureDays", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 28 + } + }, + { + "name": "tagList", + "in": "query", + "schema": { + "type": "string", + "default": "" + } + }, + { + "name": "unmonitored", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/command": { + "post": { + "tags": [ + "Command" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CommandResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/CommandResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/CommandResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/CommandResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CommandResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/CommandResource" + } + } + } + } + } + }, + "get": { + "tags": [ + "Command" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CommandResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CommandResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CommandResource" + } + } + } + } + } + } + } + }, + "/api/v1/command/{id}": { + "delete": { + "tags": [ + "Command" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + }, + "get": { + "tags": [ + "Command" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CommandResource" + } + } + } + } + } + } + }, + "/api/v1/customfilter": { + "get": { + "tags": [ + "CustomFilter" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CustomFilterResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CustomFilterResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CustomFilterResource" + } + } + } + } + } + } + }, + "post": { + "tags": [ + "CustomFilter" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CustomFilterResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/CustomFilterResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/CustomFilterResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/CustomFilterResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CustomFilterResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/CustomFilterResource" + } + } + } + } + } + } + }, + "/api/v1/customfilter/{id}": { + "put": { + "tags": [ + "CustomFilter" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CustomFilterResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/CustomFilterResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/CustomFilterResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/CustomFilterResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CustomFilterResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/CustomFilterResource" + } + } + } + } + } + }, + "delete": { + "tags": [ + "CustomFilter" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + }, + "get": { + "tags": [ + "CustomFilter" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CustomFilterResource" + } + } + } + } + } + } + }, + "/api/v1/customformat": { + "post": { + "tags": [ + "CustomFormat" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CustomFormatResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/CustomFormatResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CustomFormatResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/CustomFormatResource" + } + } + } + } + } + }, + "get": { + "tags": [ + "CustomFormat" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CustomFormatResource" + } + } + } + } + } + } + } + }, + "/api/v1/customformat/{id}": { + "put": { + "tags": [ + "CustomFormat" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CustomFormatResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/CustomFormatResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CustomFormatResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/CustomFormatResource" + } + } + } + } + } + }, + "delete": { + "tags": [ + "CustomFormat" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + }, + "get": { + "tags": [ + "CustomFormat" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CustomFormatResource" + } + } + } + } + } + } + }, + "/api/v1/customformat/schema": { + "get": { + "tags": [ + "CustomFormat" + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/wanted/cutoff": { + "get": { + "tags": [ + "Cutoff" + ], + "parameters": [ + { + "name": "page", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 1 + } + }, + { + "name": "pageSize", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 10 + } + }, + { + "name": "sortKey", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "sortDirection", + "in": "query", + "schema": { + "$ref": "#/components/schemas/SortDirection" + } + }, + { + "name": "includeAuthor", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "name": "monitored", + "in": "query", + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/BookResourcePagingResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/BookResourcePagingResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/BookResourcePagingResource" + } + } + } + } + } + } + }, + "/api/v1/wanted/cutoff/{id}": { + "get": { + "tags": [ + "Cutoff" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BookResource" + } + } + } + } + } + } + }, + "/api/v1/delayprofile": { + "post": { + "tags": [ + "DelayProfile" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DelayProfileResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/DelayProfileResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/DelayProfileResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/DelayProfileResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/DelayProfileResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/DelayProfileResource" + } + } + } + } + } + }, + "get": { + "tags": [ + "DelayProfile" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DelayProfileResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DelayProfileResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DelayProfileResource" + } + } + } + } + } + } + } + }, + "/api/v1/delayprofile/{id}": { + "delete": { + "tags": [ + "DelayProfile" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + }, + "put": { + "tags": [ + "DelayProfile" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DelayProfileResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/DelayProfileResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/DelayProfileResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/DelayProfileResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/DelayProfileResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/DelayProfileResource" + } + } + } + } + } + }, + "get": { + "tags": [ + "DelayProfile" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DelayProfileResource" + } + } + } + } + } + } + }, + "/api/v1/delayprofile/reorder/{id}": { + "put": { + "tags": [ + "DelayProfile" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "afterId", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/config/development": { + "get": { + "tags": [ + "DevelopmentConfig" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/DevelopmentConfigResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/DevelopmentConfigResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/DevelopmentConfigResource" + } + } + } + } + } + } + }, + "/api/v1/config/development/{id}": { + "put": { + "tags": [ + "DevelopmentConfig" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DevelopmentConfigResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/DevelopmentConfigResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/DevelopmentConfigResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/DevelopmentConfigResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/DevelopmentConfigResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/DevelopmentConfigResource" + } + } + } + } + } + }, + "get": { + "tags": [ + "DevelopmentConfig" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DevelopmentConfigResource" + } + } + } + } + } + } + }, + "/api/v1/diskspace": { + "get": { + "tags": [ + "DiskSpace" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DiskSpaceResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DiskSpaceResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DiskSpaceResource" + } + } + } + } + } + } + } + }, + "/api/v1/downloadclient": { + "get": { + "tags": [ + "DownloadClient" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DownloadClientResource" + } + } + } + } + } + } + }, + "post": { + "tags": [ + "DownloadClient" + ], + "parameters": [ + { + "name": "forceSave", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientResource" + } + } + } + } + } + } + }, + "/api/v1/downloadclient/{id}": { + "put": { + "tags": [ + "DownloadClient" + ], + "parameters": [ + { + "name": "forceSave", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientResource" + } + } + } + } + } + }, + "delete": { + "tags": [ + "DownloadClient" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + }, + "get": { + "tags": [ + "DownloadClient" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientResource" + } + } + } + } + } + } + }, + "/api/v1/downloadclient/bulk": { + "put": { + "tags": [ + "DownloadClient" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientBulkResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientResource" + } + } + } + } + } + }, + "delete": { + "tags": [ + "DownloadClient" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientBulkResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/downloadclient/schema": { + "get": { + "tags": [ + "DownloadClient" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DownloadClientResource" + } + } + } + } + } + } + } + }, + "/api/v1/downloadclient/test": { + "post": { + "tags": [ + "DownloadClient" + ], + "parameters": [ + { + "name": "forceTest", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/downloadclient/testall": { + "post": { + "tags": [ + "DownloadClient" + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/downloadclient/action/{name}": { + "post": { + "tags": [ + "DownloadClient" + ], + "parameters": [ + { + "name": "name", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/config/downloadclient": { + "get": { + "tags": [ + "DownloadClientConfig" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/DownloadClientConfigResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientConfigResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientConfigResource" + } + } + } + } + } + } + }, + "/api/v1/config/downloadclient/{id}": { + "put": { + "tags": [ + "DownloadClientConfig" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientConfigResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientConfigResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientConfigResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/DownloadClientConfigResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientConfigResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientConfigResource" + } + } + } + } + } + }, + "get": { + "tags": [ + "DownloadClientConfig" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientConfigResource" + } + } + } + } + } + } + }, + "/api/v1/edition": { + "get": { + "tags": [ + "Edition" + ], + "parameters": [ + { + "name": "bookId", + "in": "query", + "schema": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + } + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EditionResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EditionResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EditionResource" + } + } + } + } + } + } + } + }, + "/api/v1/filesystem": { + "get": { + "tags": [ + "FileSystem" + ], + "parameters": [ + { + "name": "path", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "includeFiles", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "name": "allowFoldersWithoutTrailingSlashes", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/filesystem/type": { + "get": { + "tags": [ + "FileSystem" + ], + "parameters": [ + { + "name": "path", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/filesystem/mediafiles": { + "get": { + "tags": [ + "FileSystem" + ], + "parameters": [ + { + "name": "path", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/health": { + "get": { + "tags": [ + "Health" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/HealthResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/HealthResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/HealthResource" + } + } + } + } + } + } + } + }, + "/api/v1/history": { + "get": { + "tags": [ + "History" + ], + "parameters": [ + { + "name": "page", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 1 + } + }, + { + "name": "pageSize", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 10 + } + }, + { + "name": "sortKey", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "sortDirection", + "in": "query", + "schema": { + "$ref": "#/components/schemas/SortDirection" + } + }, + { + "name": "includeAuthor", + "in": "query", + "schema": { + "type": "boolean" + } + }, + { + "name": "includeBook", + "in": "query", + "schema": { + "type": "boolean" + } + }, + { + "name": "eventType", + "in": "query", + "schema": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + } + } + }, + { + "name": "bookId", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "downloadId", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HistoryResourcePagingResource" + } + } + } + } + } + } + }, + "/api/v1/history/since": { + "get": { + "tags": [ + "History" + ], + "parameters": [ + { + "name": "date", + "in": "query", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "eventType", + "in": "query", + "schema": { + "$ref": "#/components/schemas/EntityHistoryEventType" + } + }, + { + "name": "includeAuthor", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "name": "includeBook", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/HistoryResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/HistoryResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/HistoryResource" + } + } + } + } + } + } + } + }, + "/api/v1/history/author": { + "get": { + "tags": [ + "History" + ], + "parameters": [ + { + "name": "authorId", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "bookId", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "eventType", + "in": "query", + "schema": { + "$ref": "#/components/schemas/EntityHistoryEventType" + } + }, + { + "name": "includeAuthor", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "name": "includeBook", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/HistoryResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/HistoryResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/HistoryResource" + } + } + } + } + } + } + } + }, + "/api/v1/history/failed/{id}": { + "post": { + "tags": [ + "History" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/config/host": { + "get": { + "tags": [ + "HostConfig" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/HostConfigResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/HostConfigResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/HostConfigResource" + } + } + } + } + } + } + }, + "/api/v1/config/host/{id}": { + "put": { + "tags": [ + "HostConfig" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HostConfigResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/HostConfigResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/HostConfigResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/HostConfigResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/HostConfigResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/HostConfigResource" + } + } + } + } + } + }, + "get": { + "tags": [ + "HostConfig" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HostConfigResource" + } + } + } + } + } + } + }, + "/api/v1/importlist": { + "get": { + "tags": [ + "ImportList" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ImportListResource" + } + } + } + } + } + } + }, + "post": { + "tags": [ + "ImportList" + ], + "parameters": [ + { + "name": "forceSave", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ImportListResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ImportListResource" + } + } + } + } + } + } + }, + "/api/v1/importlist/{id}": { + "put": { + "tags": [ + "ImportList" + ], + "parameters": [ + { + "name": "forceSave", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ImportListResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ImportListResource" + } + } + } + } + } + }, + "delete": { + "tags": [ + "ImportList" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + }, + "get": { + "tags": [ + "ImportList" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ImportListResource" + } + } + } + } + } + } + }, + "/api/v1/importlist/bulk": { + "put": { + "tags": [ + "ImportList" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ImportListBulkResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ImportListResource" + } + } + } + } + } + }, + "delete": { + "tags": [ + "ImportList" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ImportListBulkResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/importlist/schema": { + "get": { + "tags": [ + "ImportList" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ImportListResource" + } + } + } + } + } + } + } + }, + "/api/v1/importlist/test": { + "post": { + "tags": [ + "ImportList" + ], + "parameters": [ + { + "name": "forceTest", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ImportListResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/importlist/testall": { + "post": { + "tags": [ + "ImportList" + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/importlist/action/{name}": { + "post": { + "tags": [ + "ImportList" + ], + "parameters": [ + { + "name": "name", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ImportListResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/importlistexclusion": { + "get": { + "tags": [ + "ImportListExclusion" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ImportListExclusionResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ImportListExclusionResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ImportListExclusionResource" + } + } + } + } + } + } + }, + "post": { + "tags": [ + "ImportListExclusion" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ImportListExclusionResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/ImportListExclusionResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/ImportListExclusionResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/ImportListExclusionResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/ImportListExclusionResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/ImportListExclusionResource" + } + } + } + } + } + } + }, + "/api/v1/importlistexclusion/{id}": { + "put": { + "tags": [ + "ImportListExclusion" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ImportListExclusionResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/ImportListExclusionResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/ImportListExclusionResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/ImportListExclusionResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/ImportListExclusionResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/ImportListExclusionResource" + } + } + } + } + } + }, + "delete": { + "tags": [ + "ImportListExclusion" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + }, + "get": { + "tags": [ + "ImportListExclusion" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ImportListExclusionResource" + } + } + } + } + } + } + }, + "/api/v1/indexer": { + "get": { + "tags": [ + "Indexer" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IndexerResource" + } + } + } + } + } + } + }, + "post": { + "tags": [ + "Indexer" + ], + "parameters": [ + { + "name": "forceSave", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerResource" + } + } + } + } + } + } + }, + "/api/v1/indexer/{id}": { + "put": { + "tags": [ + "Indexer" + ], + "parameters": [ + { + "name": "forceSave", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerResource" + } + } + } + } + } + }, + "delete": { + "tags": [ + "Indexer" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + }, + "get": { + "tags": [ + "Indexer" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerResource" + } + } + } + } + } + } + }, + "/api/v1/indexer/bulk": { + "put": { + "tags": [ + "Indexer" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerBulkResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerResource" + } + } + } + } + } + }, + "delete": { + "tags": [ + "Indexer" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerBulkResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/indexer/schema": { + "get": { + "tags": [ + "Indexer" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IndexerResource" + } + } + } + } + } + } + } + }, + "/api/v1/indexer/test": { + "post": { + "tags": [ + "Indexer" + ], + "parameters": [ + { + "name": "forceTest", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/indexer/testall": { + "post": { + "tags": [ + "Indexer" + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/indexer/action/{name}": { + "post": { + "tags": [ + "Indexer" + ], + "parameters": [ + { + "name": "name", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/config/indexer": { + "get": { + "tags": [ + "IndexerConfig" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/IndexerConfigResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerConfigResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/IndexerConfigResource" + } + } + } + } + } + } + }, + "/api/v1/config/indexer/{id}": { + "put": { + "tags": [ + "IndexerConfig" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerConfigResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/IndexerConfigResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/IndexerConfigResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/IndexerConfigResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerConfigResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/IndexerConfigResource" + } + } + } + } + } + }, + "get": { + "tags": [ + "IndexerConfig" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerConfigResource" + } + } + } + } + } + } + }, + "/api/v1/indexerflag": { + "get": { + "tags": [ + "IndexerFlag" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IndexerFlagResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IndexerFlagResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IndexerFlagResource" + } + } + } + } + } + } + } + }, + "/api/v1/language": { + "get": { + "tags": [ + "Language" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LanguageResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LanguageResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LanguageResource" + } + } + } + } + } + } + } + }, + "/api/v1/language/{id}": { + "get": { + "tags": [ + "Language" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LanguageResource" + } + } + } + } + } + } + }, + "/api/v1/localization": { + "get": { + "tags": [ + "Localization" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + }, + "application/json": { + "schema": { + "type": "string" + } + }, + "text/json": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/api/v1/log": { + "get": { + "tags": [ + "Log" + ], + "parameters": [ + { + "name": "page", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 1 + } + }, + { + "name": "pageSize", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 10 + } + }, + { + "name": "sortKey", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "sortDirection", + "in": "query", + "schema": { + "$ref": "#/components/schemas/SortDirection" + } + }, + { + "name": "level", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LogResourcePagingResource" + } + } + } + } + } + } + }, + "/api/v1/log/file": { + "get": { + "tags": [ + "LogFile" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LogFileResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LogFileResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LogFileResource" + } + } + } + } + } + } + } + }, + "/api/v1/log/file/{filename}": { + "get": { + "tags": [ + "LogFile" + ], + "parameters": [ + { + "name": "filename", + "in": "path", + "required": true, + "schema": { + "pattern": "[-.a-zA-Z0-9]+?\\.txt", + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/manualimport": { + "post": { + "tags": [ + "ManualImport" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ManualImportUpdateResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ManualImportUpdateResource" + } + } + }, + "application/*+json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ManualImportUpdateResource" + } + } + } + } + }, + "responses": { + "200": { + "description": "OK" + } + } + }, + "get": { + "tags": [ + "ManualImport" + ], + "parameters": [ + { + "name": "folder", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "downloadId", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "authorId", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "filterExistingFiles", + "in": "query", + "schema": { + "type": "boolean", + "default": true + } + }, + { + "name": "replaceExistingFiles", + "in": "query", + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ManualImportResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ManualImportResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ManualImportResource" + } + } + } + } + } + } + } + }, + "/api/v1/mediacover/author/{authorId}/{filename}": { + "get": { + "tags": [ + "MediaCover" + ], + "parameters": [ + { + "name": "authorId", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "filename", + "in": "path", + "required": true, + "schema": { + "pattern": "(.+)\\.(jpg|png|gif)", + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/mediacover/book/{bookId}/{filename}": { + "get": { + "tags": [ + "MediaCover" + ], + "parameters": [ + { + "name": "bookId", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "filename", + "in": "path", + "required": true, + "schema": { + "pattern": "(.+)\\.(jpg|png|gif)", + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/config/mediamanagement": { + "get": { + "tags": [ + "MediaManagementConfig" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/MediaManagementConfigResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/MediaManagementConfigResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/MediaManagementConfigResource" + } + } + } + } + } + } + }, + "/api/v1/config/mediamanagement/{id}": { + "put": { + "tags": [ + "MediaManagementConfig" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MediaManagementConfigResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/MediaManagementConfigResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/MediaManagementConfigResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/MediaManagementConfigResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/MediaManagementConfigResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/MediaManagementConfigResource" + } + } + } + } + } + }, + "get": { + "tags": [ + "MediaManagementConfig" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MediaManagementConfigResource" + } + } + } + } + } + } + }, + "/api/v1/metadata": { + "get": { + "tags": [ + "Metadata" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MetadataResource" + } + } + } + } + } + } + }, + "post": { + "tags": [ + "Metadata" + ], + "parameters": [ + { + "name": "forceSave", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MetadataResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MetadataResource" + } + } + } + } + } + } + }, + "/api/v1/metadata/{id}": { + "put": { + "tags": [ + "Metadata" + ], + "parameters": [ + { + "name": "forceSave", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MetadataResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MetadataResource" + } + } + } + } + } + }, + "delete": { + "tags": [ + "Metadata" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + }, + "get": { + "tags": [ + "Metadata" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MetadataResource" + } + } + } + } + } + } + }, + "/api/v1/metadata/schema": { + "get": { + "tags": [ + "Metadata" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MetadataResource" + } + } + } + } + } + } + } + }, + "/api/v1/metadata/test": { + "post": { + "tags": [ + "Metadata" + ], + "parameters": [ + { + "name": "forceTest", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MetadataResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/metadata/testall": { + "post": { + "tags": [ + "Metadata" + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/metadata/action/{name}": { + "post": { + "tags": [ + "Metadata" + ], + "parameters": [ + { + "name": "name", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MetadataResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/metadataprofile": { + "post": { + "tags": [ + "MetadataProfile" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MetadataProfileResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/MetadataProfileResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/MetadataProfileResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/MetadataProfileResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/MetadataProfileResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/MetadataProfileResource" + } + } + } + } + } + }, + "get": { + "tags": [ + "MetadataProfile" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MetadataProfileResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MetadataProfileResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MetadataProfileResource" + } + } + } + } + } + } + } + }, + "/api/v1/metadataprofile/{id}": { + "delete": { + "tags": [ + "MetadataProfile" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + }, + "put": { + "tags": [ + "MetadataProfile" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MetadataProfileResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/MetadataProfileResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/MetadataProfileResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/MetadataProfileResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/MetadataProfileResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/MetadataProfileResource" + } + } + } + } + } + }, + "get": { + "tags": [ + "MetadataProfile" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MetadataProfileResource" + } + } + } + } + } + } + }, + "/api/v1/metadataprofile/schema": { + "get": { + "tags": [ + "MetadataProfileSchema" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/MetadataProfileResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/MetadataProfileResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/MetadataProfileResource" + } + } + } + } + } + } + }, + "/api/v1/config/metadataprovider": { + "get": { + "tags": [ + "MetadataProviderConfig" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/MetadataProviderConfigResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/MetadataProviderConfigResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/MetadataProviderConfigResource" + } + } + } + } + } + } + }, + "/api/v1/config/metadataprovider/{id}": { + "put": { + "tags": [ + "MetadataProviderConfig" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MetadataProviderConfigResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/MetadataProviderConfigResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/MetadataProviderConfigResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/MetadataProviderConfigResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/MetadataProviderConfigResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/MetadataProviderConfigResource" + } + } + } + } + } + }, + "get": { + "tags": [ + "MetadataProviderConfig" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MetadataProviderConfigResource" + } + } + } + } + } + } + }, + "/api/v1/wanted/missing": { + "get": { + "tags": [ + "Missing" + ], + "parameters": [ + { + "name": "page", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 1 + } + }, + { + "name": "pageSize", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 10 + } + }, + { + "name": "sortKey", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "sortDirection", + "in": "query", + "schema": { + "$ref": "#/components/schemas/SortDirection" + } + }, + { + "name": "includeAuthor", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "name": "monitored", + "in": "query", + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/BookResourcePagingResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/BookResourcePagingResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/BookResourcePagingResource" + } + } + } + } + } + } + }, + "/api/v1/wanted/missing/{id}": { + "get": { + "tags": [ + "Missing" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BookResource" + } + } + } + } + } + } + }, + "/api/v1/config/naming": { + "get": { + "tags": [ + "NamingConfig" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/NamingConfigResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/NamingConfigResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/NamingConfigResource" + } + } + } + } + } + } + }, + "/api/v1/config/naming/{id}": { + "put": { + "tags": [ + "NamingConfig" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NamingConfigResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/NamingConfigResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/NamingConfigResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/NamingConfigResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/NamingConfigResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/NamingConfigResource" + } + } + } + } + } + }, + "get": { + "tags": [ + "NamingConfig" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NamingConfigResource" + } + } + } + } + } + } + }, + "/api/v1/config/naming/examples": { + "get": { + "tags": [ + "NamingConfig" + ], + "parameters": [ + { + "name": "renameBooks", + "in": "query", + "schema": { + "type": "boolean" + } + }, + { + "name": "replaceIllegalCharacters", + "in": "query", + "schema": { + "type": "boolean" + } + }, + { + "name": "colonReplacementFormat", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "standardBookFormat", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "authorFolderFormat", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "includeAuthorName", + "in": "query", + "schema": { + "type": "boolean" + } + }, + { + "name": "includeBookTitle", + "in": "query", + "schema": { + "type": "boolean" + } + }, + { + "name": "includeQuality", + "in": "query", + "schema": { + "type": "boolean" + } + }, + { + "name": "replaceSpaces", + "in": "query", + "schema": { + "type": "boolean" + } + }, + { + "name": "separator", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "numberStyle", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "id", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "resourceName", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/notification": { + "get": { + "tags": [ + "Notification" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/NotificationResource" + } + } + } + } + } + } + }, + "post": { + "tags": [ + "Notification" + ], + "parameters": [ + { + "name": "forceSave", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationResource" + } + } + } + } + } + } + }, + "/api/v1/notification/{id}": { + "put": { + "tags": [ + "Notification" + ], + "parameters": [ + { + "name": "forceSave", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationResource" + } + } + } + } + } + }, + "delete": { + "tags": [ + "Notification" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + }, + "get": { + "tags": [ + "Notification" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationResource" + } + } + } + } + } + } + }, + "/api/v1/notification/schema": { + "get": { + "tags": [ + "Notification" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/NotificationResource" + } + } + } + } + } + } + } + }, + "/api/v1/notification/test": { + "post": { + "tags": [ + "Notification" + ], + "parameters": [ + { + "name": "forceTest", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/notification/testall": { + "post": { + "tags": [ + "Notification" + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/notification/action/{name}": { + "post": { + "tags": [ + "Notification" + ], + "parameters": [ + { + "name": "name", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/parse": { + "get": { + "tags": [ + "Parse" + ], + "parameters": [ + { + "name": "title", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/ParseResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/ParseResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/ParseResource" + } + } + } + } + } + } + }, + "/ping": { + "get": { + "tags": [ + "Ping" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PingResource" + } + } + } + } + } + }, + "head": { + "tags": [ + "Ping" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PingResource" + } + } + } + } + } + } + }, + "/api/v1/qualitydefinition/{id}": { + "put": { + "tags": [ + "QualityDefinition" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/QualityDefinitionResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/QualityDefinitionResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/QualityDefinitionResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/QualityDefinitionResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/QualityDefinitionResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/QualityDefinitionResource" + } + } + } + } + } + }, + "get": { + "tags": [ + "QualityDefinition" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/QualityDefinitionResource" + } + } + } + } + } + } + }, + "/api/v1/qualitydefinition": { + "get": { + "tags": [ + "QualityDefinition" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/QualityDefinitionResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/QualityDefinitionResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/QualityDefinitionResource" + } + } + } + } + } + } + } + }, + "/api/v1/qualitydefinition/update": { + "put": { + "tags": [ + "QualityDefinition" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/QualityDefinitionResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/QualityDefinitionResource" + } + } + }, + "application/*+json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/QualityDefinitionResource" + } + } + } + } + }, + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/qualityprofile": { + "post": { + "tags": [ + "QualityProfile" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/QualityProfileResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/QualityProfileResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/QualityProfileResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/QualityProfileResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/QualityProfileResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/QualityProfileResource" + } + } + } + } + } + }, + "get": { + "tags": [ + "QualityProfile" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/QualityProfileResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/QualityProfileResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/QualityProfileResource" + } + } + } + } + } + } + } + }, + "/api/v1/qualityprofile/{id}": { + "delete": { + "tags": [ + "QualityProfile" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + }, + "put": { + "tags": [ + "QualityProfile" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/QualityProfileResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/QualityProfileResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/QualityProfileResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/QualityProfileResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/QualityProfileResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/QualityProfileResource" + } + } + } + } + } + }, + "get": { + "tags": [ + "QualityProfile" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/QualityProfileResource" + } + } + } + } + } + } + }, + "/api/v1/qualityprofile/schema": { + "get": { + "tags": [ + "QualityProfileSchema" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/QualityProfileResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/QualityProfileResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/QualityProfileResource" + } + } + } + } + } + } + }, + "/api/v1/queue/{id}": { + "delete": { + "tags": [ + "Queue" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "removeFromClient", + "in": "query", + "schema": { + "type": "boolean", + "default": true + } + }, + { + "name": "blocklist", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "name": "skipRedownload", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "name": "changeCategory", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/queue/bulk": { + "delete": { + "tags": [ + "Queue" + ], + "parameters": [ + { + "name": "removeFromClient", + "in": "query", + "schema": { + "type": "boolean", + "default": true + } + }, + { + "name": "blocklist", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "name": "skipRedownload", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "name": "changeCategory", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/QueueBulkResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/QueueBulkResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/QueueBulkResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/queue": { + "get": { + "tags": [ + "Queue" + ], + "parameters": [ + { + "name": "page", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 1 + } + }, + { + "name": "pageSize", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 10 + } + }, + { + "name": "sortKey", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "sortDirection", + "in": "query", + "schema": { + "$ref": "#/components/schemas/SortDirection" + } + }, + { + "name": "includeUnknownAuthorItems", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "name": "includeAuthor", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "name": "includeBook", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/QueueResourcePagingResource" + } + } + } + } + } + } + }, + "/api/v1/queue/grab/{id}": { + "post": { + "tags": [ + "QueueAction" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/queue/grab/bulk": { + "post": { + "tags": [ + "QueueAction" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/QueueBulkResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/queue/details": { + "get": { + "tags": [ + "QueueDetails" + ], + "parameters": [ + { + "name": "authorId", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "bookIds", + "in": "query", + "schema": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + } + } + }, + { + "name": "includeAuthor", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "name": "includeBook", + "in": "query", + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/QueueResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/QueueResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/QueueResource" + } + } + } + } + } + } + } + }, + "/api/v1/queue/status": { + "get": { + "tags": [ + "QueueStatus" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/QueueStatusResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/QueueStatusResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/QueueStatusResource" + } + } + } + } + } + } + }, + "/api/v1/release": { + "post": { + "tags": [ + "Release" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ReleaseResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/ReleaseResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/ReleaseResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/ReleaseResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/ReleaseResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/ReleaseResource" + } + } + } + } + } + }, + "get": { + "tags": [ + "Release" + ], + "parameters": [ + { + "name": "bookId", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "authorId", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ReleaseResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ReleaseResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ReleaseResource" + } + } + } + } + } + } + } + }, + "/api/v1/releaseprofile": { + "get": { + "tags": [ + "ReleaseProfile" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ReleaseProfileResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ReleaseProfileResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ReleaseProfileResource" + } + } + } + } + } + } + }, + "post": { + "tags": [ + "ReleaseProfile" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ReleaseProfileResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/ReleaseProfileResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/ReleaseProfileResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/ReleaseProfileResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/ReleaseProfileResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/ReleaseProfileResource" + } + } + } + } + } + } + }, + "/api/v1/releaseprofile/{id}": { + "put": { + "tags": [ + "ReleaseProfile" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ReleaseProfileResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/ReleaseProfileResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/ReleaseProfileResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/ReleaseProfileResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/ReleaseProfileResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/ReleaseProfileResource" + } + } + } + } + } + }, + "delete": { + "tags": [ + "ReleaseProfile" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + }, + "get": { + "tags": [ + "ReleaseProfile" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ReleaseProfileResource" + } + } + } + } + } + } + }, + "/api/v1/release/push": { + "post": { + "tags": [ + "ReleasePush" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ReleaseResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/ReleaseResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/ReleaseResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/ReleaseResource" + } + } + } + } + } + } + }, + "/api/v1/remotepathmapping": { + "post": { + "tags": [ + "RemotePathMapping" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RemotePathMappingResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/RemotePathMappingResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/RemotePathMappingResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/RemotePathMappingResource" + } + } + } + } + } + }, + "get": { + "tags": [ + "RemotePathMapping" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RemotePathMappingResource" + } + } + } + } + } + } + } + }, + "/api/v1/remotepathmapping/{id}": { + "delete": { + "tags": [ + "RemotePathMapping" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + }, + "put": { + "tags": [ + "RemotePathMapping" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RemotePathMappingResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/RemotePathMappingResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/RemotePathMappingResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/RemotePathMappingResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/RemotePathMappingResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/RemotePathMappingResource" + } + } + } + } + } + }, + "get": { + "tags": [ + "RemotePathMapping" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RemotePathMappingResource" + } + } + } + } + } + } + }, + "/api/v1/rename": { + "get": { + "tags": [ + "RenameBook" + ], + "parameters": [ + { + "name": "authorId", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "bookId", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RenameBookResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RenameBookResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RenameBookResource" + } + } + } + } + } + } + } + }, + "/api/v1/retag": { + "get": { + "tags": [ + "RetagBook" + ], + "parameters": [ + { + "name": "authorId", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "bookId", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RetagBookResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RetagBookResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RetagBookResource" + } + } + } + } + } + } + } + }, + "/api/v1/rootfolder": { + "post": { + "tags": [ + "RootFolder" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RootFolderResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/RootFolderResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/RootFolderResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/RootFolderResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/RootFolderResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/RootFolderResource" + } + } + } + } + } + }, + "get": { + "tags": [ + "RootFolder" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RootFolderResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RootFolderResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RootFolderResource" + } + } + } + } + } + } + } + }, + "/api/v1/rootfolder/{id}": { + "put": { + "tags": [ + "RootFolder" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RootFolderResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/RootFolderResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/RootFolderResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/RootFolderResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/RootFolderResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/RootFolderResource" + } + } + } + } + } + }, + "delete": { + "tags": [ + "RootFolder" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + }, + "get": { + "tags": [ + "RootFolder" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RootFolderResource" + } + } + } + } + } + } + }, + "/api/v1/search": { + "get": { + "tags": [ + "Search" + ], + "parameters": [ + { + "name": "term", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/series": { + "get": { + "tags": [ + "Series" + ], + "parameters": [ + { + "name": "authorId", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SeriesResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SeriesResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SeriesResource" + } + } + } + } + } + } + } + }, + "/content/{path}": { + "get": { + "tags": [ + "StaticResource" + ], + "parameters": [ + { + "name": "path", + "in": "path", + "required": true, + "schema": { + "pattern": "^(?!/*api/).*", + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/": { + "get": { + "tags": [ + "StaticResource" + ], + "parameters": [ + { + "name": "path", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/{path}": { + "get": { + "tags": [ + "StaticResource" + ], + "parameters": [ + { + "name": "path", + "in": "path", + "required": true, + "schema": { + "pattern": "^(?!(api|feed)/).*", + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/system/status": { + "get": { + "tags": [ + "System" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/SystemResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/SystemResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/SystemResource" + } + } + } + } + } + } + }, + "/api/v1/system/routes": { + "get": { + "tags": [ + "System" + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/system/routes/duplicate": { + "get": { + "tags": [ + "System" + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/system/shutdown": { + "post": { + "tags": [ + "System" + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/system/restart": { + "post": { + "tags": [ + "System" + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/tag": { + "get": { + "tags": [ + "Tag" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TagResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TagResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TagResource" + } + } + } + } + } + } + }, + "post": { + "tags": [ + "Tag" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/TagResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/TagResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/TagResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/TagResource" + } + } + } + } + } + } + }, + "/api/v1/tag/{id}": { + "put": { + "tags": [ + "Tag" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/TagResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/TagResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/TagResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/TagResource" + } + } + } + } + } + }, + "delete": { + "tags": [ + "Tag" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + }, + "get": { + "tags": [ + "Tag" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagResource" + } + } + } + } + } + } + }, + "/api/v1/tag/detail": { + "get": { + "tags": [ + "TagDetails" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TagDetailsResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TagDetailsResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TagDetailsResource" + } + } + } + } + } + } + } + }, + "/api/v1/tag/detail/{id}": { + "get": { + "tags": [ + "TagDetails" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagDetailsResource" + } + } + } + } + } + } + }, + "/api/v1/system/task": { + "get": { + "tags": [ + "Task" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TaskResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TaskResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TaskResource" + } + } + } + } + } + } + } + }, + "/api/v1/system/task/{id}": { + "get": { + "tags": [ + "Task" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TaskResource" + } + } + } + } + } + } + }, + "/api/v1/config/ui/{id}": { + "put": { + "tags": [ + "UiConfig" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UiConfigResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/UiConfigResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/UiConfigResource" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/UiConfigResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/UiConfigResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/UiConfigResource" + } + } + } + } + } + }, + "get": { + "tags": [ + "UiConfig" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UiConfigResource" + } + } + } + } + } + } + }, + "/api/v1/config/ui": { + "get": { + "tags": [ + "UiConfig" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/UiConfigResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/UiConfigResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/UiConfigResource" + } + } + } + } + } + } + }, + "/api/v1/update": { + "get": { + "tags": [ + "Update" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/UpdateResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/UpdateResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/UpdateResource" + } + } + } + } + } + } + } + }, + "/api/v1/log/file/update": { + "get": { + "tags": [ + "UpdateLogFile" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LogFileResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LogFileResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LogFileResource" + } + } + } + } + } + } + } + }, + "/api/v1/log/file/update/{filename}": { + "get": { + "tags": [ + "UpdateLogFile" + ], + "parameters": [ + { + "name": "filename", + "in": "path", + "required": true, + "schema": { + "pattern": "[-.a-zA-Z0-9]+?\\.txt", + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + } + }, + "components": { + "schemas": { + "AddAuthorOptions": { + "type": "object", + "properties": { + "monitor": { + "$ref": "#/components/schemas/MonitorTypes" + }, + "booksToMonitor": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "monitored": { + "type": "boolean" + }, + "searchForMissingBooks": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "AddBookOptions": { + "type": "object", + "properties": { + "addType": { + "$ref": "#/components/schemas/BookAddType" + }, + "searchForNewBook": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "AllowFingerprinting": { + "enum": [ + "never", + "newFiles", + "allFiles" + ], + "type": "string" + }, + "ApiInfoResource": { + "type": "object", + "properties": { + "current": { + "type": "string", + "nullable": true + }, + "deprecated": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "ApplyTags": { + "enum": [ + "add", + "remove", + "replace" + ], + "type": "string" + }, + "AuthenticationRequiredType": { + "enum": [ + "enabled", + "disabledForLocalAddresses" + ], + "type": "string" + }, + "AuthenticationType": { + "enum": [ + "none", + "basic", + "forms", + "external" + ], + "type": "string" + }, + "Author": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "authorMetadataId": { + "type": "integer", + "format": "int32" + }, + "cleanName": { + "type": "string", + "nullable": true + }, + "monitored": { + "type": "boolean" + }, + "monitorNewItems": { + "$ref": "#/components/schemas/NewItemMonitorTypes" + }, + "lastInfoSync": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "path": { + "type": "string", + "nullable": true + }, + "rootFolderPath": { + "type": "string", + "nullable": true + }, + "added": { + "type": "string", + "format": "date-time" + }, + "qualityProfileId": { + "type": "integer", + "format": "int32" + }, + "metadataProfileId": { + "type": "integer", + "format": "int32" + }, + "tags": { + "uniqueItems": true, + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + }, + "addOptions": { + "$ref": "#/components/schemas/AddAuthorOptions" + }, + "metadata": { + "$ref": "#/components/schemas/AuthorMetadataLazyLoaded" + }, + "qualityProfile": { + "$ref": "#/components/schemas/QualityProfileLazyLoaded" + }, + "metadataProfile": { + "$ref": "#/components/schemas/MetadataProfileLazyLoaded" + }, + "books": { + "$ref": "#/components/schemas/BookListLazyLoaded" + }, + "series": { + "$ref": "#/components/schemas/SeriesListLazyLoaded" + }, + "name": { + "type": "string", + "nullable": true + }, + "foreignAuthorId": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "AuthorEditorResource": { + "type": "object", + "properties": { + "authorIds": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + }, + "monitored": { + "type": "boolean", + "nullable": true + }, + "monitorNewItems": { + "$ref": "#/components/schemas/NewItemMonitorTypes" + }, + "qualityProfileId": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "metadataProfileId": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "rootFolderPath": { + "type": "string", + "nullable": true + }, + "tags": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + }, + "applyTags": { + "$ref": "#/components/schemas/ApplyTags" + }, + "moveFiles": { + "type": "boolean" + }, + "deleteFiles": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "AuthorLazyLoaded": { + "type": "object", + "properties": { + "value": { + "$ref": "#/components/schemas/Author" + }, + "isLoaded": { + "type": "boolean", + "readOnly": true + } + }, + "additionalProperties": false + }, + "AuthorMetadata": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "foreignAuthorId": { + "type": "string", + "nullable": true + }, + "titleSlug": { + "type": "string", + "nullable": true + }, + "name": { + "type": "string", + "nullable": true + }, + "sortName": { + "type": "string", + "nullable": true + }, + "nameLastFirst": { + "type": "string", + "nullable": true + }, + "sortNameLastFirst": { + "type": "string", + "nullable": true + }, + "aliases": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "overview": { + "type": "string", + "nullable": true + }, + "disambiguation": { + "type": "string", + "nullable": true + }, + "gender": { + "type": "string", + "nullable": true + }, + "hometown": { + "type": "string", + "nullable": true + }, + "born": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "died": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "status": { + "$ref": "#/components/schemas/AuthorStatusType" + }, + "images": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MediaCover" + }, + "nullable": true + }, + "links": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Links" + }, + "nullable": true + }, + "genres": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "ratings": { + "$ref": "#/components/schemas/Ratings" + } + }, + "additionalProperties": false + }, + "AuthorMetadataLazyLoaded": { + "type": "object", + "properties": { + "value": { + "$ref": "#/components/schemas/AuthorMetadata" + }, + "isLoaded": { + "type": "boolean", + "readOnly": true + } + }, + "additionalProperties": false + }, + "AuthorResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "authorMetadataId": { + "type": "integer", + "format": "int32" + }, + "status": { + "$ref": "#/components/schemas/AuthorStatusType" + }, + "ended": { + "type": "boolean", + "readOnly": true + }, + "authorName": { + "type": "string", + "nullable": true + }, + "authorNameLastFirst": { + "type": "string", + "nullable": true + }, + "foreignAuthorId": { + "type": "string", + "nullable": true + }, + "titleSlug": { + "type": "string", + "nullable": true + }, + "overview": { + "type": "string", + "nullable": true + }, + "disambiguation": { + "type": "string", + "nullable": true + }, + "links": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Links" + }, + "nullable": true + }, + "nextBook": { + "$ref": "#/components/schemas/Book" + }, + "lastBook": { + "$ref": "#/components/schemas/Book" + }, + "images": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MediaCover" + }, + "nullable": true + }, + "remotePoster": { + "type": "string", + "nullable": true + }, + "path": { + "type": "string", + "nullable": true + }, + "qualityProfileId": { + "type": "integer", + "format": "int32" + }, + "metadataProfileId": { + "type": "integer", + "format": "int32" + }, + "monitored": { + "type": "boolean" + }, + "monitorNewItems": { + "$ref": "#/components/schemas/NewItemMonitorTypes" + }, + "rootFolderPath": { + "type": "string", + "nullable": true + }, + "folder": { + "type": "string", + "nullable": true + }, + "genres": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "cleanName": { + "type": "string", + "nullable": true + }, + "sortName": { + "type": "string", + "nullable": true + }, + "sortNameLastFirst": { + "type": "string", + "nullable": true + }, + "tags": { + "uniqueItems": true, + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + }, + "added": { + "type": "string", + "format": "date-time" + }, + "addOptions": { + "$ref": "#/components/schemas/AddAuthorOptions" + }, + "ratings": { + "$ref": "#/components/schemas/Ratings" + }, + "statistics": { + "$ref": "#/components/schemas/AuthorStatisticsResource" + } + }, + "additionalProperties": false + }, + "AuthorStatisticsResource": { + "type": "object", + "properties": { + "bookFileCount": { + "type": "integer", + "format": "int32" + }, + "bookCount": { + "type": "integer", + "format": "int32" + }, + "availableBookCount": { + "type": "integer", + "format": "int32" + }, + "totalBookCount": { + "type": "integer", + "format": "int32" + }, + "sizeOnDisk": { + "type": "integer", + "format": "int64" + }, + "percentOfBooks": { + "type": "number", + "format": "double", + "readOnly": true + } + }, + "additionalProperties": false + }, + "AuthorStatusType": { + "enum": [ + "continuing", + "ended" + ], + "type": "string" + }, + "AuthorTitleInfo": { + "type": "object", + "properties": { + "title": { + "type": "string", + "nullable": true + }, + "titleWithoutYear": { + "type": "string", + "nullable": true + }, + "year": { + "type": "integer", + "format": "int32" + } + }, + "additionalProperties": false + }, + "BackupResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string", + "nullable": true + }, + "path": { + "type": "string", + "nullable": true + }, + "type": { + "$ref": "#/components/schemas/BackupType" + }, + "size": { + "type": "integer", + "format": "int64" + }, + "time": { + "type": "string", + "format": "date-time" + } + }, + "additionalProperties": false + }, + "BackupType": { + "enum": [ + "scheduled", + "manual", + "update" + ], + "type": "string" + }, + "BlocklistBulkResource": { + "type": "object", + "properties": { + "ids": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "BlocklistResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "authorId": { + "type": "integer", + "format": "int32" + }, + "bookIds": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + }, + "sourceTitle": { + "type": "string", + "nullable": true + }, + "quality": { + "$ref": "#/components/schemas/QualityModel" + }, + "customFormats": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CustomFormatResource" + }, + "nullable": true + }, + "date": { + "type": "string", + "format": "date-time" + }, + "protocol": { + "$ref": "#/components/schemas/DownloadProtocol" + }, + "indexer": { + "type": "string", + "nullable": true + }, + "message": { + "type": "string", + "nullable": true + }, + "author": { + "$ref": "#/components/schemas/AuthorResource" + } + }, + "additionalProperties": false + }, + "BlocklistResourcePagingResource": { + "type": "object", + "properties": { + "page": { + "type": "integer", + "format": "int32" + }, + "pageSize": { + "type": "integer", + "format": "int32" + }, + "sortKey": { + "type": "string", + "nullable": true + }, + "sortDirection": { + "$ref": "#/components/schemas/SortDirection" + }, + "totalRecords": { + "type": "integer", + "format": "int32" + }, + "records": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BlocklistResource" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "Book": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "authorMetadataId": { + "type": "integer", + "format": "int32" + }, + "foreignBookId": { + "type": "string", + "nullable": true + }, + "foreignEditionId": { + "type": "string", + "nullable": true + }, + "titleSlug": { + "type": "string", + "nullable": true + }, + "title": { + "type": "string", + "nullable": true + }, + "releaseDate": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "links": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Links" + }, + "nullable": true + }, + "genres": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "relatedBooks": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + }, + "ratings": { + "$ref": "#/components/schemas/Ratings" + }, + "lastSearchTime": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "cleanTitle": { + "type": "string", + "nullable": true + }, + "monitored": { + "type": "boolean" + }, + "anyEditionOk": { + "type": "boolean" + }, + "lastInfoSync": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "added": { + "type": "string", + "format": "date-time" + }, + "addOptions": { + "$ref": "#/components/schemas/AddBookOptions" + }, + "authorMetadata": { + "$ref": "#/components/schemas/AuthorMetadataLazyLoaded" + }, + "author": { + "$ref": "#/components/schemas/AuthorLazyLoaded" + }, + "editions": { + "$ref": "#/components/schemas/EditionListLazyLoaded" + }, + "bookFiles": { + "$ref": "#/components/schemas/BookFileListLazyLoaded" + }, + "seriesLinks": { + "$ref": "#/components/schemas/SeriesBookLinkListLazyLoaded" + } + }, + "additionalProperties": false + }, + "BookAddType": { + "enum": [ + "automatic", + "manual" + ], + "type": "string" + }, + "BookEditorResource": { + "type": "object", + "properties": { + "bookIds": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + }, + "monitored": { + "type": "boolean", + "nullable": true + }, + "deleteFiles": { + "type": "boolean", + "nullable": true + }, + "addImportListExclusion": { + "type": "boolean", + "nullable": true + } + }, + "additionalProperties": false + }, + "BookFile": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "path": { + "type": "string", + "nullable": true + }, + "size": { + "type": "integer", + "format": "int64" + }, + "modified": { + "type": "string", + "format": "date-time" + }, + "dateAdded": { + "type": "string", + "format": "date-time" + }, + "originalFilePath": { + "type": "string", + "nullable": true + }, + "sceneName": { + "type": "string", + "nullable": true + }, + "releaseGroup": { + "type": "string", + "nullable": true + }, + "quality": { + "$ref": "#/components/schemas/QualityModel" + }, + "indexerFlags": { + "$ref": "#/components/schemas/IndexerFlags" + }, + "mediaInfo": { + "$ref": "#/components/schemas/MediaInfoModel" + }, + "editionId": { + "type": "integer", + "format": "int32" + }, + "calibreId": { + "type": "integer", + "format": "int32" + }, + "part": { + "type": "integer", + "format": "int32" + }, + "author": { + "$ref": "#/components/schemas/AuthorLazyLoaded" + }, + "edition": { + "$ref": "#/components/schemas/EditionLazyLoaded" + }, + "partCount": { + "type": "integer", + "format": "int32" + } + }, + "additionalProperties": false + }, + "BookFileListLazyLoaded": { + "type": "object", + "properties": { + "value": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BookFile" + }, + "nullable": true, + "readOnly": true + }, + "isLoaded": { + "type": "boolean", + "readOnly": true + } + }, + "additionalProperties": false + }, + "BookFileListResource": { + "type": "object", + "properties": { + "bookFileIds": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + }, + "quality": { + "$ref": "#/components/schemas/QualityModel" + } + }, + "additionalProperties": false + }, + "BookFileResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "authorId": { + "type": "integer", + "format": "int32" + }, + "bookId": { + "type": "integer", + "format": "int32" + }, + "path": { + "type": "string", + "nullable": true + }, + "size": { + "type": "integer", + "format": "int64" + }, + "dateAdded": { + "type": "string", + "format": "date-time" + }, + "quality": { + "$ref": "#/components/schemas/QualityModel" + }, + "qualityWeight": { + "type": "integer", + "format": "int32" + }, + "indexerFlags": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "mediaInfo": { + "$ref": "#/components/schemas/MediaInfoResource" + }, + "qualityCutoffNotMet": { + "type": "boolean" + }, + "audioTags": { + "$ref": "#/components/schemas/ParsedTrackInfo" + } + }, + "additionalProperties": false + }, + "BookLazyLoaded": { + "type": "object", + "properties": { + "value": { + "$ref": "#/components/schemas/Book" + }, + "isLoaded": { + "type": "boolean", + "readOnly": true + } + }, + "additionalProperties": false + }, + "BookListLazyLoaded": { + "type": "object", + "properties": { + "value": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Book" + }, + "nullable": true, + "readOnly": true + }, + "isLoaded": { + "type": "boolean", + "readOnly": true + } + }, + "additionalProperties": false + }, + "BookResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "title": { + "type": "string", + "nullable": true + }, + "authorTitle": { + "type": "string", + "nullable": true + }, + "seriesTitle": { + "type": "string", + "nullable": true + }, + "disambiguation": { + "type": "string", + "nullable": true + }, + "overview": { + "type": "string", + "nullable": true + }, + "authorId": { + "type": "integer", + "format": "int32" + }, + "foreignBookId": { + "type": "string", + "nullable": true + }, + "foreignEditionId": { + "type": "string", + "nullable": true + }, + "titleSlug": { + "type": "string", + "nullable": true + }, + "monitored": { + "type": "boolean" + }, + "anyEditionOk": { + "type": "boolean" + }, + "ratings": { + "$ref": "#/components/schemas/Ratings" + }, + "releaseDate": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "pageCount": { + "type": "integer", + "format": "int32" + }, + "genres": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "author": { + "$ref": "#/components/schemas/AuthorResource" + }, + "images": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MediaCover" + }, + "nullable": true + }, + "links": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Links" + }, + "nullable": true + }, + "statistics": { + "$ref": "#/components/schemas/BookStatisticsResource" + }, + "added": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "addOptions": { + "$ref": "#/components/schemas/AddBookOptions" + }, + "remoteCover": { + "type": "string", + "nullable": true + }, + "lastSearchTime": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "editions": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EditionResource" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "BookResourcePagingResource": { + "type": "object", + "properties": { + "page": { + "type": "integer", + "format": "int32" + }, + "pageSize": { + "type": "integer", + "format": "int32" + }, + "sortKey": { + "type": "string", + "nullable": true + }, + "sortDirection": { + "$ref": "#/components/schemas/SortDirection" + }, + "totalRecords": { + "type": "integer", + "format": "int32" + }, + "records": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BookResource" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "BookStatisticsResource": { + "type": "object", + "properties": { + "bookFileCount": { + "type": "integer", + "format": "int32" + }, + "bookCount": { + "type": "integer", + "format": "int32" + }, + "totalBookCount": { + "type": "integer", + "format": "int32" + }, + "sizeOnDisk": { + "type": "integer", + "format": "int64" + }, + "percentOfBooks": { + "type": "number", + "format": "double", + "readOnly": true + } + }, + "additionalProperties": false + }, + "BooksMonitoredResource": { + "type": "object", + "properties": { + "bookIds": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + }, + "monitored": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "BookshelfAuthorResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "monitored": { + "type": "boolean", + "nullable": true + }, + "books": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BookResource" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "BookshelfResource": { + "type": "object", + "properties": { + "authors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BookshelfAuthorResource" + }, + "nullable": true + }, + "monitoringOptions": { + "$ref": "#/components/schemas/MonitoringOptions" + }, + "monitorNewItems": { + "$ref": "#/components/schemas/NewItemMonitorTypes" + } + }, + "additionalProperties": false + }, + "CertificateValidationType": { + "enum": [ + "enabled", + "disabledForLocalAddresses", + "disabled" + ], + "type": "string" + }, + "Command": { + "type": "object", + "properties": { + "sendUpdatesToClient": { + "type": "boolean" + }, + "updateScheduledTask": { + "type": "boolean", + "readOnly": true + }, + "completionMessage": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "requiresDiskAccess": { + "type": "boolean", + "readOnly": true + }, + "isExclusive": { + "type": "boolean", + "readOnly": true + }, + "isTypeExclusive": { + "type": "boolean", + "readOnly": true + }, + "isLongRunning": { + "type": "boolean", + "readOnly": true + }, + "name": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "lastExecutionTime": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "lastStartTime": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "trigger": { + "$ref": "#/components/schemas/CommandTrigger" + }, + "suppressMessages": { + "type": "boolean" + }, + "clientUserAgent": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "CommandPriority": { + "enum": [ + "normal", + "high", + "low" + ], + "type": "string" + }, + "CommandResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string", + "nullable": true + }, + "commandName": { + "type": "string", + "nullable": true + }, + "message": { + "type": "string", + "nullable": true + }, + "body": { + "$ref": "#/components/schemas/Command" + }, + "priority": { + "$ref": "#/components/schemas/CommandPriority" + }, + "status": { + "$ref": "#/components/schemas/CommandStatus" + }, + "result": { + "$ref": "#/components/schemas/CommandResult" + }, + "queued": { + "type": "string", + "format": "date-time" + }, + "started": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "ended": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "duration": { + "type": "string", + "format": "date-span", + "nullable": true + }, + "exception": { + "type": "string", + "nullable": true + }, + "trigger": { + "$ref": "#/components/schemas/CommandTrigger" + }, + "clientUserAgent": { + "type": "string", + "nullable": true + }, + "stateChangeTime": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "sendUpdatesToClient": { + "type": "boolean" + }, + "updateScheduledTask": { + "type": "boolean" + }, + "lastExecutionTime": { + "type": "string", + "format": "date-time", + "nullable": true + } + }, + "additionalProperties": false + }, + "CommandResult": { + "enum": [ + "unknown", + "successful", + "unsuccessful" + ], + "type": "string" + }, + "CommandStatus": { + "enum": [ + "queued", + "started", + "completed", + "failed", + "aborted", + "cancelled", + "orphaned" + ], + "type": "string" + }, + "CommandTrigger": { + "enum": [ + "unspecified", + "manual", + "scheduled" + ], + "type": "string" + }, + "CustomFilterResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "type": { + "type": "string", + "nullable": true + }, + "label": { + "type": "string", + "nullable": true + }, + "filters": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": { } + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "CustomFormat": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string", + "nullable": true + }, + "includeCustomFormatWhenRenaming": { + "type": "boolean" + }, + "specifications": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ICustomFormatSpecification" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "CustomFormatResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string", + "nullable": true + }, + "includeCustomFormatWhenRenaming": { + "type": "boolean", + "nullable": true + }, + "specifications": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CustomFormatSpecificationSchema" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "CustomFormatSpecificationSchema": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string", + "nullable": true + }, + "implementation": { + "type": "string", + "nullable": true + }, + "implementationName": { + "type": "string", + "nullable": true + }, + "infoLink": { + "type": "string", + "nullable": true + }, + "negate": { + "type": "boolean" + }, + "required": { + "type": "boolean" + }, + "fields": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Field" + }, + "nullable": true + }, + "presets": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CustomFormatSpecificationSchema" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "DatabaseType": { + "enum": [ + "sqLite", + "postgreSQL" + ], + "type": "string" + }, + "DelayProfileResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "enableUsenet": { + "type": "boolean" + }, + "enableTorrent": { + "type": "boolean" + }, + "preferredProtocol": { + "$ref": "#/components/schemas/DownloadProtocol" + }, + "usenetDelay": { + "type": "integer", + "format": "int32" + }, + "torrentDelay": { + "type": "integer", + "format": "int32" + }, + "bypassIfHighestQuality": { + "type": "boolean" + }, + "bypassIfAboveCustomFormatScore": { + "type": "boolean" + }, + "minimumCustomFormatScore": { + "type": "integer", + "format": "int32" + }, + "order": { + "type": "integer", + "format": "int32" + }, + "tags": { + "uniqueItems": true, + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "DevelopmentConfigResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "metadataSource": { + "type": "string", + "nullable": true + }, + "consoleLogLevel": { + "type": "string", + "nullable": true + }, + "logSql": { + "type": "boolean" + }, + "logRotate": { + "type": "integer", + "format": "int32" + }, + "filterSentryEvents": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "DiskSpaceResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "path": { + "type": "string", + "nullable": true + }, + "label": { + "type": "string", + "nullable": true + }, + "freeSpace": { + "type": "integer", + "format": "int64" + }, + "totalSpace": { + "type": "integer", + "format": "int64" + } + }, + "additionalProperties": false + }, + "DownloadClientBulkResource": { + "type": "object", + "properties": { + "ids": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + }, + "tags": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + }, + "applyTags": { + "$ref": "#/components/schemas/ApplyTags" + }, + "enable": { + "type": "boolean", + "nullable": true + }, + "priority": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "removeCompletedDownloads": { + "type": "boolean", + "nullable": true + }, + "removeFailedDownloads": { + "type": "boolean", + "nullable": true + } + }, + "additionalProperties": false + }, + "DownloadClientConfigResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "downloadClientWorkingFolders": { + "type": "string", + "nullable": true + }, + "enableCompletedDownloadHandling": { + "type": "boolean" + }, + "autoRedownloadFailed": { + "type": "boolean" + }, + "autoRedownloadFailedFromInteractiveSearch": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "DownloadClientResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string", + "nullable": true + }, + "fields": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Field" + }, + "nullable": true + }, + "implementationName": { + "type": "string", + "nullable": true + }, + "implementation": { + "type": "string", + "nullable": true + }, + "configContract": { + "type": "string", + "nullable": true + }, + "infoLink": { + "type": "string", + "nullable": true + }, + "message": { + "$ref": "#/components/schemas/ProviderMessage" + }, + "tags": { + "uniqueItems": true, + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + }, + "presets": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DownloadClientResource" + }, + "nullable": true + }, + "enable": { + "type": "boolean" + }, + "protocol": { + "$ref": "#/components/schemas/DownloadProtocol" + }, + "priority": { + "type": "integer", + "format": "int32" + }, + "removeCompletedDownloads": { + "type": "boolean" + }, + "removeFailedDownloads": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "DownloadProtocol": { + "enum": [ + "unknown", + "usenet", + "torrent" + ], + "type": "string" + }, + "Edition": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "bookId": { + "type": "integer", + "format": "int32" + }, + "foreignEditionId": { + "type": "string", + "nullable": true + }, + "titleSlug": { + "type": "string", + "nullable": true + }, + "isbn13": { + "type": "string", + "nullable": true + }, + "asin": { + "type": "string", + "nullable": true + }, + "title": { + "type": "string", + "nullable": true + }, + "language": { + "type": "string", + "nullable": true + }, + "overview": { + "type": "string", + "nullable": true + }, + "format": { + "type": "string", + "nullable": true + }, + "isEbook": { + "type": "boolean" + }, + "disambiguation": { + "type": "string", + "nullable": true + }, + "publisher": { + "type": "string", + "nullable": true + }, + "pageCount": { + "type": "integer", + "format": "int32" + }, + "releaseDate": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "images": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MediaCover" + }, + "nullable": true + }, + "links": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Links" + }, + "nullable": true + }, + "ratings": { + "$ref": "#/components/schemas/Ratings" + }, + "monitored": { + "type": "boolean" + }, + "manualAdd": { + "type": "boolean" + }, + "book": { + "$ref": "#/components/schemas/BookLazyLoaded" + }, + "bookFiles": { + "$ref": "#/components/schemas/BookFileListLazyLoaded" + } + }, + "additionalProperties": false + }, + "EditionLazyLoaded": { + "type": "object", + "properties": { + "value": { + "$ref": "#/components/schemas/Edition" + }, + "isLoaded": { + "type": "boolean", + "readOnly": true + } + }, + "additionalProperties": false + }, + "EditionListLazyLoaded": { + "type": "object", + "properties": { + "value": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Edition" + }, + "nullable": true, + "readOnly": true + }, + "isLoaded": { + "type": "boolean", + "readOnly": true + } + }, + "additionalProperties": false + }, + "EditionResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "bookId": { + "type": "integer", + "format": "int32" + }, + "foreignEditionId": { + "type": "string", + "nullable": true + }, + "titleSlug": { + "type": "string", + "nullable": true + }, + "isbn13": { + "type": "string", + "nullable": true + }, + "asin": { + "type": "string", + "nullable": true + }, + "title": { + "type": "string", + "nullable": true + }, + "language": { + "type": "string", + "nullable": true + }, + "overview": { + "type": "string", + "nullable": true + }, + "format": { + "type": "string", + "nullable": true + }, + "isEbook": { + "type": "boolean" + }, + "disambiguation": { + "type": "string", + "nullable": true + }, + "publisher": { + "type": "string", + "nullable": true + }, + "pageCount": { + "type": "integer", + "format": "int32" + }, + "releaseDate": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "images": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MediaCover" + }, + "nullable": true + }, + "links": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Links" + }, + "nullable": true + }, + "ratings": { + "$ref": "#/components/schemas/Ratings" + }, + "monitored": { + "type": "boolean" + }, + "manualAdd": { + "type": "boolean" + }, + "remoteCover": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "EntityHistoryEventType": { + "enum": [ + "unknown", + "grabbed", + "bookFileImported", + "downloadFailed", + "bookFileDeleted", + "bookFileRenamed", + "bookImportIncomplete", + "downloadImported", + "bookFileRetagged", + "downloadIgnored" + ], + "type": "string" + }, + "Field": { + "type": "object", + "properties": { + "order": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string", + "nullable": true + }, + "label": { + "type": "string", + "nullable": true + }, + "unit": { + "type": "string", + "nullable": true + }, + "helpText": { + "type": "string", + "nullable": true + }, + "helpTextWarning": { + "type": "string", + "nullable": true + }, + "helpLink": { + "type": "string", + "nullable": true + }, + "value": { + "nullable": true + }, + "type": { + "type": "string", + "nullable": true + }, + "advanced": { + "type": "boolean" + }, + "selectOptions": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SelectOption" + }, + "nullable": true + }, + "selectOptionsProviderAction": { + "type": "string", + "nullable": true + }, + "section": { + "type": "string", + "nullable": true + }, + "hidden": { + "type": "string", + "nullable": true + }, + "placeholder": { + "type": "string", + "nullable": true + }, + "isFloat": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "FileDateType": { + "enum": [ + "none", + "bookReleaseDate" + ], + "type": "string" + }, + "HealthCheckResult": { + "enum": [ + "ok", + "notice", + "warning", + "error" + ], + "type": "string" + }, + "HealthResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "source": { + "type": "string", + "nullable": true + }, + "type": { + "$ref": "#/components/schemas/HealthCheckResult" + }, + "message": { + "type": "string", + "nullable": true + }, + "wikiUrl": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "HistoryResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "bookId": { + "type": "integer", + "format": "int32" + }, + "authorId": { + "type": "integer", + "format": "int32" + }, + "sourceTitle": { + "type": "string", + "nullable": true + }, + "quality": { + "$ref": "#/components/schemas/QualityModel" + }, + "customFormats": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CustomFormatResource" + }, + "nullable": true + }, + "customFormatScore": { + "type": "integer", + "format": "int32" + }, + "qualityCutoffNotMet": { + "type": "boolean" + }, + "date": { + "type": "string", + "format": "date-time" + }, + "downloadId": { + "type": "string", + "nullable": true + }, + "eventType": { + "$ref": "#/components/schemas/EntityHistoryEventType" + }, + "data": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "nullable": true + }, + "book": { + "$ref": "#/components/schemas/BookResource" + }, + "author": { + "$ref": "#/components/schemas/AuthorResource" + } + }, + "additionalProperties": false + }, + "HistoryResourcePagingResource": { + "type": "object", + "properties": { + "page": { + "type": "integer", + "format": "int32" + }, + "pageSize": { + "type": "integer", + "format": "int32" + }, + "sortKey": { + "type": "string", + "nullable": true + }, + "sortDirection": { + "$ref": "#/components/schemas/SortDirection" + }, + "totalRecords": { + "type": "integer", + "format": "int32" + }, + "records": { + "type": "array", + "items": { + "$ref": "#/components/schemas/HistoryResource" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "HostConfigResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "bindAddress": { + "type": "string", + "nullable": true + }, + "port": { + "type": "integer", + "format": "int32" + }, + "sslPort": { + "type": "integer", + "format": "int32" + }, + "enableSsl": { + "type": "boolean" + }, + "launchBrowser": { + "type": "boolean" + }, + "authenticationMethod": { + "$ref": "#/components/schemas/AuthenticationType" + }, + "authenticationRequired": { + "$ref": "#/components/schemas/AuthenticationRequiredType" + }, + "analyticsEnabled": { + "type": "boolean" + }, + "username": { + "type": "string", + "nullable": true + }, + "password": { + "type": "string", + "nullable": true + }, + "passwordConfirmation": { + "type": "string", + "nullable": true + }, + "logLevel": { + "type": "string", + "nullable": true + }, + "consoleLogLevel": { + "type": "string", + "nullable": true + }, + "branch": { + "type": "string", + "nullable": true + }, + "apiKey": { + "type": "string", + "nullable": true + }, + "sslCertPath": { + "type": "string", + "nullable": true + }, + "sslCertPassword": { + "type": "string", + "nullable": true + }, + "urlBase": { + "type": "string", + "nullable": true + }, + "instanceName": { + "type": "string", + "nullable": true + }, + "applicationUrl": { + "type": "string", + "nullable": true + }, + "updateAutomatically": { + "type": "boolean" + }, + "updateMechanism": { + "$ref": "#/components/schemas/UpdateMechanism" + }, + "updateScriptPath": { + "type": "string", + "nullable": true + }, + "proxyEnabled": { + "type": "boolean" + }, + "proxyType": { + "$ref": "#/components/schemas/ProxyType" + }, + "proxyHostname": { + "type": "string", + "nullable": true + }, + "proxyPort": { + "type": "integer", + "format": "int32" + }, + "proxyUsername": { + "type": "string", + "nullable": true + }, + "proxyPassword": { + "type": "string", + "nullable": true + }, + "proxyBypassFilter": { + "type": "string", + "nullable": true + }, + "proxyBypassLocalAddresses": { + "type": "boolean" + }, + "certificateValidation": { + "$ref": "#/components/schemas/CertificateValidationType" + }, + "backupFolder": { + "type": "string", + "nullable": true + }, + "backupInterval": { + "type": "integer", + "format": "int32" + }, + "backupRetention": { + "type": "integer", + "format": "int32" + }, + "trustCgnatIpAddresses": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "ICustomFormatSpecification": { + "type": "object", + "properties": { + "order": { + "type": "integer", + "format": "int32", + "readOnly": true + }, + "infoLink": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "implementationName": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "name": { + "type": "string", + "nullable": true + }, + "negate": { + "type": "boolean" + }, + "required": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "ImportListBulkResource": { + "type": "object", + "properties": { + "ids": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + }, + "tags": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + }, + "applyTags": { + "$ref": "#/components/schemas/ApplyTags" + }, + "enableAutomaticAdd": { + "type": "boolean", + "nullable": true + }, + "rootFolderPath": { + "type": "string", + "nullable": true + }, + "qualityProfileId": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "metadataProfileId": { + "type": "integer", + "format": "int32", + "nullable": true + } + }, + "additionalProperties": false + }, + "ImportListExclusionResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "foreignId": { + "type": "string", + "nullable": true + }, + "authorName": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "ImportListMonitorType": { + "enum": [ + "none", + "specificBook", + "entireAuthor" + ], + "type": "string" + }, + "ImportListResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string", + "nullable": true + }, + "fields": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Field" + }, + "nullable": true + }, + "implementationName": { + "type": "string", + "nullable": true + }, + "implementation": { + "type": "string", + "nullable": true + }, + "configContract": { + "type": "string", + "nullable": true + }, + "infoLink": { + "type": "string", + "nullable": true + }, + "message": { + "$ref": "#/components/schemas/ProviderMessage" + }, + "tags": { + "uniqueItems": true, + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + }, + "presets": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ImportListResource" + }, + "nullable": true + }, + "enableAutomaticAdd": { + "type": "boolean" + }, + "shouldMonitor": { + "$ref": "#/components/schemas/ImportListMonitorType" + }, + "shouldMonitorExisting": { + "type": "boolean" + }, + "shouldSearch": { + "type": "boolean" + }, + "rootFolderPath": { + "type": "string", + "nullable": true + }, + "monitorNewItems": { + "$ref": "#/components/schemas/NewItemMonitorTypes" + }, + "qualityProfileId": { + "type": "integer", + "format": "int32" + }, + "metadataProfileId": { + "type": "integer", + "format": "int32" + }, + "listType": { + "$ref": "#/components/schemas/ImportListType" + }, + "listOrder": { + "type": "integer", + "format": "int32" + }, + "minRefreshInterval": { + "type": "string", + "format": "date-span" + } + }, + "additionalProperties": false + }, + "ImportListType": { + "enum": [ + "program", + "goodreads", + "other" + ], + "type": "string" + }, + "IndexerBulkResource": { + "type": "object", + "properties": { + "ids": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + }, + "tags": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + }, + "applyTags": { + "$ref": "#/components/schemas/ApplyTags" + }, + "enableRss": { + "type": "boolean", + "nullable": true + }, + "enableAutomaticSearch": { + "type": "boolean", + "nullable": true + }, + "enableInteractiveSearch": { + "type": "boolean", + "nullable": true + }, + "priority": { + "type": "integer", + "format": "int32", + "nullable": true + } + }, + "additionalProperties": false + }, + "IndexerConfigResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "minimumAge": { + "type": "integer", + "format": "int32" + }, + "maximumSize": { + "type": "integer", + "format": "int32" + }, + "retention": { + "type": "integer", + "format": "int32" + }, + "rssSyncInterval": { + "type": "integer", + "format": "int32" + } + }, + "additionalProperties": false + }, + "IndexerFlagResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string", + "nullable": true + }, + "nameLower": { + "type": "string", + "nullable": true, + "readOnly": true + } + }, + "additionalProperties": false + }, + "IndexerFlags": { + "enum": [ + "freeleech", + "halfleech", + "doubleUpload", + "internal", + "scene", + "freeleech75", + "freeleech25" + ], + "type": "string" + }, + "IndexerResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string", + "nullable": true + }, + "fields": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Field" + }, + "nullable": true + }, + "implementationName": { + "type": "string", + "nullable": true + }, + "implementation": { + "type": "string", + "nullable": true + }, + "configContract": { + "type": "string", + "nullable": true + }, + "infoLink": { + "type": "string", + "nullable": true + }, + "message": { + "$ref": "#/components/schemas/ProviderMessage" + }, + "tags": { + "uniqueItems": true, + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + }, + "presets": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IndexerResource" + }, + "nullable": true + }, + "enableRss": { + "type": "boolean" + }, + "enableAutomaticSearch": { + "type": "boolean" + }, + "enableInteractiveSearch": { + "type": "boolean" + }, + "supportsRss": { + "type": "boolean" + }, + "supportsSearch": { + "type": "boolean" + }, + "protocol": { + "$ref": "#/components/schemas/DownloadProtocol" + }, + "priority": { + "type": "integer", + "format": "int32" + }, + "downloadClientId": { + "type": "integer", + "format": "int32" + } + }, + "additionalProperties": false + }, + "IsoCountry": { + "type": "object", + "properties": { + "twoLetterCode": { + "type": "string", + "nullable": true + }, + "name": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "LanguageResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string", + "nullable": true + }, + "nameLower": { + "type": "string", + "nullable": true, + "readOnly": true + } + }, + "additionalProperties": false + }, + "Links": { + "type": "object", + "properties": { + "url": { + "type": "string", + "nullable": true + }, + "name": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "LogFileResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "filename": { + "type": "string", + "nullable": true + }, + "lastWriteTime": { + "type": "string", + "format": "date-time" + }, + "contentsUrl": { + "type": "string", + "nullable": true + }, + "downloadUrl": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "LogResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "time": { + "type": "string", + "format": "date-time" + }, + "exception": { + "type": "string", + "nullable": true + }, + "exceptionType": { + "type": "string", + "nullable": true + }, + "level": { + "type": "string", + "nullable": true + }, + "logger": { + "type": "string", + "nullable": true + }, + "message": { + "type": "string", + "nullable": true + }, + "method": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "LogResourcePagingResource": { + "type": "object", + "properties": { + "page": { + "type": "integer", + "format": "int32" + }, + "pageSize": { + "type": "integer", + "format": "int32" + }, + "sortKey": { + "type": "string", + "nullable": true + }, + "sortDirection": { + "$ref": "#/components/schemas/SortDirection" + }, + "totalRecords": { + "type": "integer", + "format": "int32" + }, + "records": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LogResource" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "ManualImportResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "path": { + "type": "string", + "nullable": true + }, + "name": { + "type": "string", + "nullable": true + }, + "size": { + "type": "integer", + "format": "int64" + }, + "author": { + "$ref": "#/components/schemas/AuthorResource" + }, + "book": { + "$ref": "#/components/schemas/BookResource" + }, + "foreignEditionId": { + "type": "string", + "nullable": true + }, + "quality": { + "$ref": "#/components/schemas/QualityModel" + }, + "releaseGroup": { + "type": "string", + "nullable": true + }, + "qualityWeight": { + "type": "integer", + "format": "int32" + }, + "downloadId": { + "type": "string", + "nullable": true + }, + "indexerFlags": { + "type": "integer", + "format": "int32" + }, + "rejections": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Rejection" + }, + "nullable": true + }, + "audioTags": { + "$ref": "#/components/schemas/ParsedTrackInfo" + }, + "additionalFile": { + "type": "boolean" + }, + "replaceExistingFiles": { + "type": "boolean" + }, + "disableReleaseSwitching": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "ManualImportUpdateResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "path": { + "type": "string", + "nullable": true + }, + "name": { + "type": "string", + "nullable": true + }, + "authorId": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "bookId": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "foreignEditionId": { + "type": "string", + "nullable": true + }, + "quality": { + "$ref": "#/components/schemas/QualityModel" + }, + "releaseGroup": { + "type": "string", + "nullable": true + }, + "indexerFlags": { + "type": "integer", + "format": "int32" + }, + "downloadId": { + "type": "string", + "nullable": true + }, + "additionalFile": { + "type": "boolean" + }, + "replaceExistingFiles": { + "type": "boolean" + }, + "disableReleaseSwitching": { + "type": "boolean" + }, + "rejections": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Rejection" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "MediaCover": { + "type": "object", + "properties": { + "url": { + "type": "string", + "nullable": true + }, + "coverType": { + "$ref": "#/components/schemas/MediaCoverTypes" + }, + "extension": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "remoteUrl": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "MediaCoverTypes": { + "enum": [ + "unknown", + "poster", + "banner", + "fanart", + "screenshot", + "headshot", + "cover", + "disc", + "logo", + "clearlogo" + ], + "type": "string" + }, + "MediaInfoModel": { + "type": "object", + "properties": { + "audioFormat": { + "type": "string", + "nullable": true + }, + "audioBitrate": { + "type": "integer", + "format": "int32" + }, + "audioChannels": { + "type": "integer", + "format": "int32" + }, + "audioBits": { + "type": "integer", + "format": "int32" + }, + "audioSampleRate": { + "type": "integer", + "format": "int32" + } + }, + "additionalProperties": false + }, + "MediaInfoResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "audioChannels": { + "type": "number", + "format": "double" + }, + "audioBitRate": { + "type": "string", + "nullable": true + }, + "audioCodec": { + "type": "string", + "nullable": true + }, + "audioBits": { + "type": "string", + "nullable": true + }, + "audioSampleRate": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "MediaManagementConfigResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "autoUnmonitorPreviouslyDownloadedBooks": { + "type": "boolean" + }, + "recycleBin": { + "type": "string", + "nullable": true + }, + "recycleBinCleanupDays": { + "type": "integer", + "format": "int32" + }, + "downloadPropersAndRepacks": { + "$ref": "#/components/schemas/ProperDownloadTypes" + }, + "createEmptyAuthorFolders": { + "type": "boolean" + }, + "deleteEmptyFolders": { + "type": "boolean" + }, + "fileDate": { + "$ref": "#/components/schemas/FileDateType" + }, + "watchLibraryForChanges": { + "type": "boolean" + }, + "rescanAfterRefresh": { + "$ref": "#/components/schemas/RescanAfterRefreshType" + }, + "allowFingerprinting": { + "$ref": "#/components/schemas/AllowFingerprinting" + }, + "setPermissionsLinux": { + "type": "boolean" + }, + "chmodFolder": { + "type": "string", + "nullable": true + }, + "chownGroup": { + "type": "string", + "nullable": true + }, + "skipFreeSpaceCheckWhenImporting": { + "type": "boolean" + }, + "minimumFreeSpaceWhenImporting": { + "type": "integer", + "format": "int32" + }, + "copyUsingHardlinks": { + "type": "boolean" + }, + "importExtraFiles": { + "type": "boolean" + }, + "extraFileExtensions": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "MetadataProfile": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string", + "nullable": true + }, + "minPopularity": { + "type": "number", + "format": "double" + }, + "skipMissingDate": { + "type": "boolean" + }, + "skipMissingIsbn": { + "type": "boolean" + }, + "skipPartsAndSets": { + "type": "boolean" + }, + "skipSeriesSecondary": { + "type": "boolean" + }, + "allowedLanguages": { + "type": "string", + "nullable": true + }, + "minPages": { + "type": "integer", + "format": "int32" + }, + "ignored": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "MetadataProfileLazyLoaded": { + "type": "object", + "properties": { + "value": { + "$ref": "#/components/schemas/MetadataProfile" + }, + "isLoaded": { + "type": "boolean", + "readOnly": true + } + }, + "additionalProperties": false + }, + "MetadataProfileResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string", + "nullable": true + }, + "minPopularity": { + "type": "number", + "format": "double" + }, + "skipMissingDate": { + "type": "boolean" + }, + "skipMissingIsbn": { + "type": "boolean" + }, + "skipPartsAndSets": { + "type": "boolean" + }, + "skipSeriesSecondary": { + "type": "boolean" + }, + "allowedLanguages": { + "type": "string", + "nullable": true + }, + "minPages": { + "type": "integer", + "format": "int32" + }, + "ignored": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "MetadataProviderConfigResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "writeAudioTags": { + "$ref": "#/components/schemas/WriteAudioTagsType" + }, + "scrubAudioTags": { + "type": "boolean" + }, + "writeBookTags": { + "$ref": "#/components/schemas/WriteBookTagsType" + }, + "updateCovers": { + "type": "boolean" + }, + "embedMetadata": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "MetadataResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string", + "nullable": true + }, + "fields": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Field" + }, + "nullable": true + }, + "implementationName": { + "type": "string", + "nullable": true + }, + "implementation": { + "type": "string", + "nullable": true + }, + "configContract": { + "type": "string", + "nullable": true + }, + "infoLink": { + "type": "string", + "nullable": true + }, + "message": { + "$ref": "#/components/schemas/ProviderMessage" + }, + "tags": { + "uniqueItems": true, + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + }, + "presets": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MetadataResource" + }, + "nullable": true + }, + "enable": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "MonitorTypes": { + "enum": [ + "all", + "future", + "missing", + "existing", + "latest", + "first", + "none", + "unknown" + ], + "type": "string" + }, + "MonitoringOptions": { + "type": "object", + "properties": { + "monitor": { + "$ref": "#/components/schemas/MonitorTypes" + }, + "booksToMonitor": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "monitored": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "NamingConfigResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "renameBooks": { + "type": "boolean" + }, + "replaceIllegalCharacters": { + "type": "boolean" + }, + "colonReplacementFormat": { + "type": "integer", + "format": "int32" + }, + "standardBookFormat": { + "type": "string", + "nullable": true + }, + "authorFolderFormat": { + "type": "string", + "nullable": true + }, + "includeAuthorName": { + "type": "boolean" + }, + "includeBookTitle": { + "type": "boolean" + }, + "includeQuality": { + "type": "boolean" + }, + "replaceSpaces": { + "type": "boolean" + }, + "separator": { + "type": "string", + "nullable": true + }, + "numberStyle": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "NewItemMonitorTypes": { + "enum": [ + "all", + "none", + "new" + ], + "type": "string" + }, + "NotificationResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string", + "nullable": true + }, + "fields": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Field" + }, + "nullable": true + }, + "implementationName": { + "type": "string", + "nullable": true + }, + "implementation": { + "type": "string", + "nullable": true + }, + "configContract": { + "type": "string", + "nullable": true + }, + "infoLink": { + "type": "string", + "nullable": true + }, + "message": { + "$ref": "#/components/schemas/ProviderMessage" + }, + "tags": { + "uniqueItems": true, + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + }, + "presets": { + "type": "array", + "items": { + "$ref": "#/components/schemas/NotificationResource" + }, + "nullable": true + }, + "link": { + "type": "string", + "nullable": true + }, + "onGrab": { + "type": "boolean" + }, + "onReleaseImport": { + "type": "boolean" + }, + "onUpgrade": { + "type": "boolean" + }, + "onRename": { + "type": "boolean" + }, + "onAuthorAdded": { + "type": "boolean" + }, + "onAuthorDelete": { + "type": "boolean" + }, + "onBookDelete": { + "type": "boolean" + }, + "onBookFileDelete": { + "type": "boolean" + }, + "onBookFileDeleteForUpgrade": { + "type": "boolean" + }, + "onHealthIssue": { + "type": "boolean" + }, + "onDownloadFailure": { + "type": "boolean" + }, + "onImportFailure": { + "type": "boolean" + }, + "onBookRetag": { + "type": "boolean" + }, + "onApplicationUpdate": { + "type": "boolean" + }, + "supportsOnGrab": { + "type": "boolean" + }, + "supportsOnReleaseImport": { + "type": "boolean" + }, + "supportsOnUpgrade": { + "type": "boolean" + }, + "supportsOnRename": { + "type": "boolean" + }, + "supportsOnAuthorAdded": { + "type": "boolean" + }, + "supportsOnAuthorDelete": { + "type": "boolean" + }, + "supportsOnBookDelete": { + "type": "boolean" + }, + "supportsOnBookFileDelete": { + "type": "boolean" + }, + "supportsOnBookFileDeleteForUpgrade": { + "type": "boolean" + }, + "supportsOnHealthIssue": { + "type": "boolean" + }, + "includeHealthWarnings": { + "type": "boolean" + }, + "supportsOnDownloadFailure": { + "type": "boolean" + }, + "supportsOnImportFailure": { + "type": "boolean" + }, + "supportsOnBookRetag": { + "type": "boolean" + }, + "supportsOnApplicationUpdate": { + "type": "boolean" + }, + "testCommand": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "ParseResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "title": { + "type": "string", + "nullable": true + }, + "parsedBookInfo": { + "$ref": "#/components/schemas/ParsedBookInfo" + }, + "author": { + "$ref": "#/components/schemas/AuthorResource" + }, + "books": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BookResource" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "ParsedBookInfo": { + "type": "object", + "properties": { + "bookTitle": { + "type": "string", + "nullable": true + }, + "authorName": { + "type": "string", + "nullable": true + }, + "authorTitleInfo": { + "$ref": "#/components/schemas/AuthorTitleInfo" + }, + "quality": { + "$ref": "#/components/schemas/QualityModel" + }, + "releaseDate": { + "type": "string", + "nullable": true + }, + "discography": { + "type": "boolean" + }, + "discographyStart": { + "type": "integer", + "format": "int32" + }, + "discographyEnd": { + "type": "integer", + "format": "int32" + }, + "releaseGroup": { + "type": "string", + "nullable": true + }, + "releaseHash": { + "type": "string", + "nullable": true + }, + "releaseVersion": { + "type": "string", + "nullable": true + }, + "releaseTitle": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "ParsedTrackInfo": { + "type": "object", + "properties": { + "title": { + "type": "string", + "nullable": true + }, + "cleanTitle": { + "type": "string", + "nullable": true + }, + "authors": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "authorTitle": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "bookTitle": { + "type": "string", + "nullable": true + }, + "seriesTitle": { + "type": "string", + "nullable": true + }, + "seriesIndex": { + "type": "string", + "nullable": true + }, + "isbn": { + "type": "string", + "nullable": true + }, + "asin": { + "type": "string", + "nullable": true + }, + "goodreadsId": { + "type": "string", + "nullable": true + }, + "authorMBId": { + "type": "string", + "nullable": true + }, + "bookMBId": { + "type": "string", + "nullable": true + }, + "releaseMBId": { + "type": "string", + "nullable": true + }, + "recordingMBId": { + "type": "string", + "nullable": true + }, + "trackMBId": { + "type": "string", + "nullable": true + }, + "discNumber": { + "type": "integer", + "format": "int32" + }, + "discCount": { + "type": "integer", + "format": "int32" + }, + "country": { + "$ref": "#/components/schemas/IsoCountry" + }, + "year": { + "type": "integer", + "format": "int32" + }, + "publisher": { + "type": "string", + "nullable": true + }, + "label": { + "type": "string", + "nullable": true + }, + "source": { + "type": "string", + "nullable": true + }, + "catalogNumber": { + "type": "string", + "nullable": true + }, + "disambiguation": { + "type": "string", + "nullable": true + }, + "duration": { + "type": "string", + "format": "date-span" + }, + "quality": { + "$ref": "#/components/schemas/QualityModel" + }, + "mediaInfo": { + "$ref": "#/components/schemas/MediaInfoModel" + }, + "trackNumbers": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + }, + "language": { + "type": "string", + "nullable": true + }, + "releaseGroup": { + "type": "string", + "nullable": true + }, + "releaseHash": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "PingResource": { + "type": "object", + "properties": { + "status": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "ProfileFormatItem": { + "type": "object", + "properties": { + "format": { + "$ref": "#/components/schemas/CustomFormat" + }, + "score": { + "type": "integer", + "format": "int32" + } + }, + "additionalProperties": false + }, + "ProfileFormatItemResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "format": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string", + "nullable": true + }, + "score": { + "type": "integer", + "format": "int32" + } + }, + "additionalProperties": false + }, + "ProperDownloadTypes": { + "enum": [ + "preferAndUpgrade", + "doNotUpgrade", + "doNotPrefer" + ], + "type": "string" + }, + "ProviderMessage": { + "type": "object", + "properties": { + "message": { + "type": "string", + "nullable": true + }, + "type": { + "$ref": "#/components/schemas/ProviderMessageType" + } + }, + "additionalProperties": false + }, + "ProviderMessageType": { + "enum": [ + "info", + "warning", + "error" + ], + "type": "string" + }, + "ProxyType": { + "enum": [ + "http", + "socks4", + "socks5" + ], + "type": "string" + }, + "Quality": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "QualityDefinitionResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "quality": { + "$ref": "#/components/schemas/Quality" + }, + "title": { + "type": "string", + "nullable": true + }, + "weight": { + "type": "integer", + "format": "int32" + }, + "minSize": { + "type": "number", + "format": "double", + "nullable": true + }, + "maxSize": { + "type": "number", + "format": "double", + "nullable": true + } + }, + "additionalProperties": false + }, + "QualityModel": { + "type": "object", + "properties": { + "quality": { + "$ref": "#/components/schemas/Quality" + }, + "revision": { + "$ref": "#/components/schemas/Revision" + } + }, + "additionalProperties": false + }, + "QualityProfile": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string", + "nullable": true + }, + "upgradeAllowed": { + "type": "boolean" + }, + "cutoff": { + "type": "integer", + "format": "int32" + }, + "minFormatScore": { + "type": "integer", + "format": "int32" + }, + "cutoffFormatScore": { + "type": "integer", + "format": "int32" + }, + "formatItems": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ProfileFormatItem" + }, + "nullable": true + }, + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/QualityProfileQualityItem" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "QualityProfileLazyLoaded": { + "type": "object", + "properties": { + "value": { + "$ref": "#/components/schemas/QualityProfile" + }, + "isLoaded": { + "type": "boolean", + "readOnly": true + } + }, + "additionalProperties": false + }, + "QualityProfileQualityItem": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string", + "nullable": true + }, + "quality": { + "$ref": "#/components/schemas/Quality" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/QualityProfileQualityItem" + }, + "nullable": true + }, + "allowed": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "QualityProfileQualityItemResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string", + "nullable": true + }, + "quality": { + "$ref": "#/components/schemas/Quality" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/QualityProfileQualityItemResource" + }, + "nullable": true + }, + "allowed": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "QualityProfileResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string", + "nullable": true + }, + "upgradeAllowed": { + "type": "boolean" + }, + "cutoff": { + "type": "integer", + "format": "int32" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/QualityProfileQualityItemResource" + }, + "nullable": true + }, + "minFormatScore": { + "type": "integer", + "format": "int32" + }, + "cutoffFormatScore": { + "type": "integer", + "format": "int32" + }, + "formatItems": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ProfileFormatItemResource" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "QueueBulkResource": { + "type": "object", + "properties": { + "ids": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "QueueResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "authorId": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "bookId": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "author": { + "$ref": "#/components/schemas/AuthorResource" + }, + "book": { + "$ref": "#/components/schemas/BookResource" + }, + "quality": { + "$ref": "#/components/schemas/QualityModel" + }, + "customFormats": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CustomFormatResource" + }, + "nullable": true + }, + "customFormatScore": { + "type": "integer", + "format": "int32" + }, + "size": { + "type": "number", + "format": "double" + }, + "title": { + "type": "string", + "nullable": true + }, + "sizeleft": { + "type": "number", + "format": "double" + }, + "timeleft": { + "type": "string", + "format": "date-span", + "nullable": true + }, + "estimatedCompletionTime": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "status": { + "type": "string", + "nullable": true + }, + "trackedDownloadStatus": { + "$ref": "#/components/schemas/TrackedDownloadStatus" + }, + "trackedDownloadState": { + "$ref": "#/components/schemas/TrackedDownloadState" + }, + "statusMessages": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TrackedDownloadStatusMessage" + }, + "nullable": true + }, + "errorMessage": { + "type": "string", + "nullable": true + }, + "downloadId": { + "type": "string", + "nullable": true + }, + "protocol": { + "$ref": "#/components/schemas/DownloadProtocol" + }, + "downloadClient": { + "type": "string", + "nullable": true + }, + "downloadClientHasPostImportCategory": { + "type": "boolean" + }, + "indexer": { + "type": "string", + "nullable": true + }, + "outputPath": { + "type": "string", + "nullable": true + }, + "downloadForced": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "QueueResourcePagingResource": { + "type": "object", + "properties": { + "page": { + "type": "integer", + "format": "int32" + }, + "pageSize": { + "type": "integer", + "format": "int32" + }, + "sortKey": { + "type": "string", + "nullable": true + }, + "sortDirection": { + "$ref": "#/components/schemas/SortDirection" + }, + "totalRecords": { + "type": "integer", + "format": "int32" + }, + "records": { + "type": "array", + "items": { + "$ref": "#/components/schemas/QueueResource" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "QueueStatusResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "totalCount": { + "type": "integer", + "format": "int32" + }, + "count": { + "type": "integer", + "format": "int32" + }, + "unknownCount": { + "type": "integer", + "format": "int32" + }, + "errors": { + "type": "boolean" + }, + "warnings": { + "type": "boolean" + }, + "unknownErrors": { + "type": "boolean" + }, + "unknownWarnings": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "Ratings": { + "type": "object", + "properties": { + "votes": { + "type": "integer", + "format": "int32" + }, + "value": { + "type": "number", + "format": "double" + }, + "popularity": { + "type": "number", + "format": "double", + "readOnly": true + } + }, + "additionalProperties": false + }, + "Rejection": { + "type": "object", + "properties": { + "reason": { + "type": "string", + "nullable": true + }, + "type": { + "$ref": "#/components/schemas/RejectionType" + } + }, + "additionalProperties": false + }, + "RejectionType": { + "enum": [ + "permanent", + "temporary" + ], + "type": "string" + }, + "ReleaseProfileResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "enabled": { + "type": "boolean" + }, + "required": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "ignored": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "indexerId": { + "type": "integer", + "format": "int32" + }, + "tags": { + "uniqueItems": true, + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "ReleaseResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "guid": { + "type": "string", + "nullable": true + }, + "quality": { + "$ref": "#/components/schemas/QualityModel" + }, + "qualityWeight": { + "type": "integer", + "format": "int32" + }, + "age": { + "type": "integer", + "format": "int32" + }, + "ageHours": { + "type": "number", + "format": "double" + }, + "ageMinutes": { + "type": "number", + "format": "double" + }, + "size": { + "type": "integer", + "format": "int64" + }, + "indexerId": { + "type": "integer", + "format": "int32" + }, + "indexer": { + "type": "string", + "nullable": true + }, + "releaseGroup": { + "type": "string", + "nullable": true + }, + "subGroup": { + "type": "string", + "nullable": true + }, + "releaseHash": { + "type": "string", + "nullable": true + }, + "title": { + "type": "string", + "nullable": true + }, + "discography": { + "type": "boolean" + }, + "sceneSource": { + "type": "boolean" + }, + "airDate": { + "type": "string", + "nullable": true + }, + "authorName": { + "type": "string", + "nullable": true + }, + "bookTitle": { + "type": "string", + "nullable": true + }, + "approved": { + "type": "boolean" + }, + "temporarilyRejected": { + "type": "boolean" + }, + "rejected": { + "type": "boolean" + }, + "rejections": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "publishDate": { + "type": "string", + "format": "date-time" + }, + "commentUrl": { + "type": "string", + "nullable": true + }, + "downloadUrl": { + "type": "string", + "nullable": true + }, + "infoUrl": { + "type": "string", + "nullable": true + }, + "downloadAllowed": { + "type": "boolean" + }, + "releaseWeight": { + "type": "integer", + "format": "int32" + }, + "customFormats": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CustomFormatResource" + }, + "nullable": true + }, + "customFormatScore": { + "type": "integer", + "format": "int32" + }, + "magnetUrl": { + "type": "string", + "nullable": true + }, + "infoHash": { + "type": "string", + "nullable": true + }, + "seeders": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "leechers": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "protocol": { + "$ref": "#/components/schemas/DownloadProtocol" + }, + "indexerFlags": { + "type": "integer", + "format": "int32" + }, + "authorId": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "bookId": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "downloadClientId": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "downloadClient": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "RemotePathMappingResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "host": { + "type": "string", + "nullable": true + }, + "remotePath": { + "type": "string", + "nullable": true + }, + "localPath": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "RenameBookResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "authorId": { + "type": "integer", + "format": "int32" + }, + "bookId": { + "type": "integer", + "format": "int32" + }, + "bookFileId": { + "type": "integer", + "format": "int32" + }, + "existingPath": { + "type": "string", + "nullable": true + }, + "newPath": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "RescanAfterRefreshType": { + "enum": [ + "always", + "afterManual", + "never" + ], + "type": "string" + }, + "RetagBookResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "authorId": { + "type": "integer", + "format": "int32" + }, + "bookId": { + "type": "integer", + "format": "int32" + }, + "trackNumbers": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + }, + "bookFileId": { + "type": "integer", + "format": "int32" + }, + "path": { + "type": "string", + "nullable": true + }, + "changes": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TagDifference" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "Revision": { + "type": "object", + "properties": { + "version": { + "type": "integer", + "format": "int32" + }, + "real": { + "type": "integer", + "format": "int32" + }, + "isRepack": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "RootFolderResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string", + "nullable": true + }, + "path": { + "type": "string", + "nullable": true + }, + "defaultMetadataProfileId": { + "type": "integer", + "format": "int32" + }, + "defaultQualityProfileId": { + "type": "integer", + "format": "int32" + }, + "defaultMonitorOption": { + "$ref": "#/components/schemas/MonitorTypes" + }, + "defaultNewItemMonitorOption": { + "$ref": "#/components/schemas/NewItemMonitorTypes" + }, + "defaultTags": { + "uniqueItems": true, + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + }, + "isCalibreLibrary": { + "type": "boolean" + }, + "host": { + "type": "string", + "nullable": true + }, + "port": { + "type": "integer", + "format": "int32" + }, + "urlBase": { + "type": "string", + "nullable": true + }, + "username": { + "type": "string", + "nullable": true + }, + "password": { + "type": "string", + "nullable": true + }, + "library": { + "type": "string", + "nullable": true + }, + "outputFormat": { + "type": "string", + "nullable": true + }, + "outputProfile": { + "type": "string", + "nullable": true + }, + "useSsl": { + "type": "boolean" + }, + "accessible": { + "type": "boolean" + }, + "freeSpace": { + "type": "integer", + "format": "int64", + "nullable": true + }, + "totalSpace": { + "type": "integer", + "format": "int64", + "nullable": true + } + }, + "additionalProperties": false + }, + "RuntimeMode": { + "enum": [ + "console", + "service", + "tray" + ], + "type": "string" + }, + "SelectOption": { + "type": "object", + "properties": { + "value": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string", + "nullable": true + }, + "order": { + "type": "integer", + "format": "int32" + }, + "hint": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "Series": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "foreignSeriesId": { + "type": "string", + "nullable": true + }, + "title": { + "type": "string", + "nullable": true + }, + "description": { + "type": "string", + "nullable": true + }, + "numbered": { + "type": "boolean" + }, + "workCount": { + "type": "integer", + "format": "int32" + }, + "primaryWorkCount": { + "type": "integer", + "format": "int32" + }, + "linkItems": { + "$ref": "#/components/schemas/SeriesBookLinkListLazyLoaded" + }, + "books": { + "$ref": "#/components/schemas/BookListLazyLoaded" + }, + "foreignAuthorId": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "SeriesBookLink": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "position": { + "type": "string", + "nullable": true + }, + "seriesPosition": { + "type": "integer", + "format": "int32" + }, + "seriesId": { + "type": "integer", + "format": "int32" + }, + "bookId": { + "type": "integer", + "format": "int32" + }, + "isPrimary": { + "type": "boolean" + }, + "series": { + "$ref": "#/components/schemas/SeriesLazyLoaded" + }, + "book": { + "$ref": "#/components/schemas/BookLazyLoaded" + } + }, + "additionalProperties": false + }, + "SeriesBookLinkListLazyLoaded": { + "type": "object", + "properties": { + "value": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SeriesBookLink" + }, + "nullable": true, + "readOnly": true + }, + "isLoaded": { + "type": "boolean", + "readOnly": true + } + }, + "additionalProperties": false + }, + "SeriesBookLinkResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "position": { + "type": "string", + "nullable": true + }, + "seriesPosition": { + "type": "integer", + "format": "int32" + }, + "seriesId": { + "type": "integer", + "format": "int32" + }, + "bookId": { + "type": "integer", + "format": "int32" + } + }, + "additionalProperties": false + }, + "SeriesLazyLoaded": { + "type": "object", + "properties": { + "value": { + "$ref": "#/components/schemas/Series" + }, + "isLoaded": { + "type": "boolean", + "readOnly": true + } + }, + "additionalProperties": false + }, + "SeriesListLazyLoaded": { + "type": "object", + "properties": { + "value": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Series" + }, + "nullable": true, + "readOnly": true + }, + "isLoaded": { + "type": "boolean", + "readOnly": true + } + }, + "additionalProperties": false + }, + "SeriesResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "title": { + "type": "string", + "nullable": true + }, + "description": { + "type": "string", + "nullable": true + }, + "links": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SeriesBookLinkResource" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "SortDirection": { + "enum": [ + "default", + "ascending", + "descending" + ], + "type": "string" + }, + "SystemResource": { + "type": "object", + "properties": { + "appName": { + "type": "string", + "nullable": true + }, + "instanceName": { + "type": "string", + "nullable": true + }, + "version": { + "type": "string", + "nullable": true + }, + "buildTime": { + "type": "string", + "format": "date-time" + }, + "isDebug": { + "type": "boolean" + }, + "isProduction": { + "type": "boolean" + }, + "isAdmin": { + "type": "boolean" + }, + "isUserInteractive": { + "type": "boolean" + }, + "startupPath": { + "type": "string", + "nullable": true + }, + "appData": { + "type": "string", + "nullable": true + }, + "osName": { + "type": "string", + "nullable": true + }, + "osVersion": { + "type": "string", + "nullable": true + }, + "isNetCore": { + "type": "boolean" + }, + "isLinux": { + "type": "boolean" + }, + "isOsx": { + "type": "boolean" + }, + "isWindows": { + "type": "boolean" + }, + "isDocker": { + "type": "boolean" + }, + "mode": { + "$ref": "#/components/schemas/RuntimeMode" + }, + "branch": { + "type": "string", + "nullable": true + }, + "databaseType": { + "$ref": "#/components/schemas/DatabaseType" + }, + "databaseVersion": { + "type": "string", + "nullable": true + }, + "authentication": { + "$ref": "#/components/schemas/AuthenticationType" + }, + "migrationVersion": { + "type": "integer", + "format": "int32" + }, + "urlBase": { + "type": "string", + "nullable": true + }, + "runtimeVersion": { + "type": "string", + "nullable": true + }, + "runtimeName": { + "type": "string", + "nullable": true + }, + "startTime": { + "type": "string", + "format": "date-time" + }, + "packageVersion": { + "type": "string", + "nullable": true + }, + "packageAuthor": { + "type": "string", + "nullable": true + }, + "packageUpdateMechanism": { + "$ref": "#/components/schemas/UpdateMechanism" + }, + "packageUpdateMechanismMessage": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "TagDetailsResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "label": { + "type": "string", + "nullable": true + }, + "delayProfileIds": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + }, + "importListIds": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + }, + "notificationIds": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + }, + "restrictionIds": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + }, + "indexerIds": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + }, + "downloadClientIds": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + }, + "authorIds": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "TagDifference": { + "type": "object", + "properties": { + "field": { + "type": "string", + "nullable": true + }, + "oldValue": { + "type": "string", + "nullable": true + }, + "newValue": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "TagResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "label": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "TaskResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string", + "nullable": true + }, + "taskName": { + "type": "string", + "nullable": true + }, + "interval": { + "type": "integer", + "format": "int32" + }, + "lastExecution": { + "type": "string", + "format": "date-time" + }, + "lastStartTime": { + "type": "string", + "format": "date-time" + }, + "nextExecution": { + "type": "string", + "format": "date-time" + }, + "lastDuration": { + "type": "string", + "format": "date-span", + "readOnly": true + } + }, + "additionalProperties": false + }, + "TrackedDownloadState": { + "enum": [ + "downloading", + "downloadFailed", + "downloadFailedPending", + "importPending", + "importing", + "importFailed", + "imported", + "ignored" + ], + "type": "string" + }, + "TrackedDownloadStatus": { + "enum": [ + "ok", + "warning", + "error" + ], + "type": "string" + }, + "TrackedDownloadStatusMessage": { + "type": "object", + "properties": { + "title": { + "type": "string", + "nullable": true + }, + "messages": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "UiConfigResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "firstDayOfWeek": { + "type": "integer", + "format": "int32" + }, + "calendarWeekColumnHeader": { + "type": "string", + "nullable": true + }, + "shortDateFormat": { + "type": "string", + "nullable": true + }, + "longDateFormat": { + "type": "string", + "nullable": true + }, + "timeFormat": { + "type": "string", + "nullable": true + }, + "showRelativeDates": { + "type": "boolean" + }, + "enableColorImpairedMode": { + "type": "boolean" + }, + "uiLanguage": { + "type": "integer", + "format": "int32" + }, + "theme": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "UpdateChanges": { + "type": "object", + "properties": { + "new": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "fixed": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "UpdateMechanism": { + "enum": [ + "builtIn", + "script", + "external", + "apt", + "docker" + ], + "type": "string" + }, + "UpdateResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "version": { + "type": "string", + "nullable": true + }, + "branch": { + "type": "string", + "nullable": true + }, + "releaseDate": { + "type": "string", + "format": "date-time" + }, + "fileName": { + "type": "string", + "nullable": true + }, + "url": { + "type": "string", + "nullable": true + }, + "installed": { + "type": "boolean" + }, + "installedOn": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "installable": { + "type": "boolean" + }, + "latest": { + "type": "boolean" + }, + "changes": { + "$ref": "#/components/schemas/UpdateChanges" + }, + "hash": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "WriteAudioTagsType": { + "enum": [ + "no", + "newFiles", + "allFiles", + "sync" + ], + "type": "string" + }, + "WriteBookTagsType": { + "enum": [ + "newFiles", + "allFiles", + "sync" + ], + "type": "string" + } + }, + "securitySchemes": { + "X-Api-Key": { + "type": "apiKey", + "description": "Apikey passed as header", + "name": "X-Api-Key", + "in": "header" + }, + "apikey": { + "type": "apiKey", + "description": "Apikey passed as query parameter", + "name": "apikey", + "in": "query" + } + } + }, + "security": [ + { + "X-Api-Key": [ ] + }, + { + "apikey": [ ] + } + ] +} \ No newline at end of file diff --git a/starrcmd/dispatcher_test.go b/starrcmd/dispatcher_test.go new file mode 100644 index 00000000..6787ff4b --- /dev/null +++ b/starrcmd/dispatcher_test.go @@ -0,0 +1,157 @@ +package starrcmd_test + +import ( + "errors" + "fmt" + "testing" + + "golift.io/starr" + "golift.io/starr/starrcmd" +) + +var errDispatcherTest = errors.New("dispatcher test error") + +func TestDispatcher_RunSonarrGrab(t *testing.T) { + t.Setenv("sonarr_eventtype", string(starrcmd.EventGrab)) + t.Setenv("sonarr_release_quality", "HDTV-720p") + t.Setenv("sonarr_series_title", "This Is Us") + t.Setenv("sonarr_release_qualityversion", "1") + t.Setenv("sonarr_series_id", "47") + t.Setenv("sonarr_release_episodenumbers", "4") + t.Setenv("sonarr_release_episodecount", "1") + t.Setenv("sonarr_download_client", "NZBGet") + t.Setenv("sonarr_release_episodeairdates", "2022-01-25") + t.Setenv("sonarr_release_episodetitles", "Don't Let Me Keep You") + t.Setenv("sonarr_release_title", "This.is.Us.S06E04.720p.HDTV.x264-SYNCOPY") + t.Setenv("sonarr_download_id", "a87bda3c0e7f40a1b8fa011b421a5201") + t.Setenv("sonarr_release_indexer", "Indexor (Prowlarr)") + t.Setenv("sonarr_series_type", "Standard") + t.Setenv("sonarr_release_size", "885369406") + t.Setenv("sonarr_series_tvdbid", "311714") + t.Setenv("sonarr_series_tvmazeid", "17128") + t.Setenv("sonarr_release_releasegroup", "SYNCOPY") + t.Setenv("sonarr_release_seasonnumber", "6") + t.Setenv("sonarr_release_absoluteepisodenumbers", "92") + t.Setenv("sonarr_series_imdbid", "tt5555260") + t.Setenv("sonarr_release_episodeairdatesutc", "1/26/2022 2:00:00 AM") + + var sawTitle string + + registry := starrcmd.NewDispatcher() + registry.Register(starr.Sonarr, starrcmd.EventGrab, func(cmd *starrcmd.CmdEvent) error { + grab, err := cmd.GetSonarrGrab() + if err != nil { + return fmt.Errorf("get sonarr grab: %w", err) + } + + sawTitle = grab.Title + + return nil + }) + + if err := registry.Run(); err != nil { + t.Fatal(err) + } + + if sawTitle != "This Is Us" { + t.Fatalf("callback title: %q", sawTitle) + } +} + +func TestDispatcher_MultipleCallbacksOrder(t *testing.T) { + t.Setenv("sonarr_eventtype", string(starrcmd.EventTest)) + + var order []int + + registry := starrcmd.NewDispatcher() + registry.Register(starr.Sonarr, starrcmd.EventTest, func(*starrcmd.CmdEvent) error { + order = append(order, 1) + + return nil + }) + registry.Register(starr.Sonarr, starrcmd.EventTest, func(*starrcmd.CmdEvent) error { + order = append(order, 2) + + return nil + }) + + if err := registry.Run(); err != nil { + t.Fatal(err) + } + + if len(order) != 2 || order[0] != 1 || order[1] != 2 { + t.Fatalf("order: %v", order) + } +} + +func TestDispatcher_OnUnknown(t *testing.T) { + t.Setenv("radarr_eventtype", string(starrcmd.EventGrab)) + t.Setenv("radarr_movie_title", "X") + + var unknown bool + + registry := starrcmd.NewDispatcher() + registry.OnUnknown = func(cmd *starrcmd.CmdEvent) error { + if cmd.App == starr.Radarr && cmd.Type == starrcmd.EventGrab { + unknown = true + } + + return nil + } + + if err := registry.Run(); err != nil { + t.Fatal(err) + } + + if !unknown { + t.Fatal("OnUnknown not called") + } +} + +func TestDispatcher_NoUnknownNoOp(t *testing.T) { + t.Setenv("prowlarr_eventtype", string(starrcmd.EventTest)) + + registry := starrcmd.NewDispatcher() + if err := registry.Run(); err != nil { + t.Fatal(err) + } +} + +func TestDispatcher_CallbackError(t *testing.T) { + t.Setenv("sonarr_eventtype", string(starrcmd.EventTest)) + + registry := starrcmd.NewDispatcher() + registry.Register(starr.Sonarr, starrcmd.EventTest, func(*starrcmd.CmdEvent) error { + return errDispatcherTest + }) + + err := registry.Run() + if err == nil || !errors.Is(err, errDispatcherTest) { + t.Fatalf("err: %v", err) + } +} + +func TestDispatcher_NilReceiver(t *testing.T) { + t.Parallel() + + var registry *starrcmd.Dispatcher + + if err := registry.Run(); !errors.Is(err, starrcmd.ErrNilDispatcher) { + t.Fatalf("Run: %v", err) + } + + if err := registry.Dispatch(&starrcmd.CmdEvent{}); !errors.Is(err, starrcmd.ErrNilDispatcher) { + t.Fatalf("Dispatch: %v", err) + } + + registry.Register(starr.Sonarr, starrcmd.EventTest, func(*starrcmd.CmdEvent) error { return nil }) // no panic +} + +func TestDispatcher_NilCmd(t *testing.T) { + t.Parallel() + + registry := starrcmd.NewDispatcher() + if err := registry.Dispatch(nil); !errors.Is(err, starrcmd.ErrNilCmdEvent) { + t.Fatalf("err: %v", err) + } +} diff --git a/starrshared/autotagging.go b/starrshared/autotagging.go new file mode 100644 index 00000000..0749384a --- /dev/null +++ b/starrshared/autotagging.go @@ -0,0 +1,23 @@ +package starrshared + +import "golift.io/starr" + +// AutoTagging is the auto tagging API resource shared by Sonarr, Lidarr, Readarr, and Radarr. +type AutoTagging struct { + ID int `json:"id,omitempty"` + Name string `json:"name,omitempty"` + RemoveTagsAutomatically bool `json:"removeTagsAutomatically"` + Tags []int `json:"tags,omitempty"` + Specifications []*AutoTaggingSpecification `json:"specifications,omitempty"` +} + +// AutoTaggingSpecification is one rule inside an AutoTagging definition. +type AutoTaggingSpecification struct { + ID int `json:"id,omitempty"` + Name string `json:"name,omitempty"` + Implementation string `json:"implementation,omitempty"` + ImplementationName string `json:"implementationName,omitempty"` + Negate bool `json:"negate"` + Required bool `json:"required"` + Fields []*starr.FieldInput `json:"fields,omitempty"` +} diff --git a/starrshared/customfilter.go b/starrshared/customfilter.go new file mode 100644 index 00000000..13a476f3 --- /dev/null +++ b/starrshared/customfilter.go @@ -0,0 +1,11 @@ +package starrshared + +import "encoding/json" + +// CustomFilter is the /customfilter resource (UI saved filters). +type CustomFilter struct { + ID int `json:"id,omitempty"` + Type string `json:"type,omitempty"` + Label string `json:"label,omitempty"` + Filters []json.RawMessage `json:"filters,omitempty"` +} diff --git a/starrshared/diskspace.go b/starrshared/diskspace.go new file mode 100644 index 00000000..29508168 --- /dev/null +++ b/starrshared/diskspace.go @@ -0,0 +1,10 @@ +package starrshared + +// DiskSpace is the /diskspace API resource shared by all Starr app clients. +type DiskSpace struct { + ID int `json:"id"` + Path string `json:"path,omitempty"` + Label string `json:"label,omitempty"` + FreeSpace int64 `json:"freeSpace"` + TotalSpace int64 `json:"totalSpace"` +} diff --git a/starrshared/doc.go b/starrshared/doc.go new file mode 100644 index 00000000..66013a92 --- /dev/null +++ b/starrshared/doc.go @@ -0,0 +1,2 @@ +// Package starrshared holds API types used by more than one Starr app client. +package starrshared diff --git a/starrshared/health.go b/starrshared/health.go new file mode 100644 index 00000000..1a3710e1 --- /dev/null +++ b/starrshared/health.go @@ -0,0 +1,10 @@ +package starrshared + +// Health is the /health API resource shared by all Starr app clients. +type Health struct { + ID int `json:"id"` + Source string `json:"source,omitempty"` + Type string `json:"type,omitempty"` + Message string `json:"message,omitempty"` + WikiURL string `json:"wikiUrl,omitempty"` +} diff --git a/starrshared/system.go b/starrshared/system.go new file mode 100644 index 00000000..3a6bc28e --- /dev/null +++ b/starrshared/system.go @@ -0,0 +1,20 @@ +package starrshared + +import "time" + +// SystemTask is a scheduled task from /system/task. +type SystemTask struct { + ID int `json:"id,omitempty"` + Name string `json:"name,omitempty"` + TaskName string `json:"taskName,omitempty"` + Interval int `json:"interval,omitempty"` + LastExecution time.Time `json:"lastExecution,omitzero"` + LastStartTime time.Time `json:"lastStartTime,omitzero"` + NextExecution time.Time `json:"nextExecution,omitzero"` + LastDuration string `json:"lastDuration,omitempty"` +} + +// BackupRestoreResponse is returned when restoring a backup. +type BackupRestoreResponse struct { + RestartRequired bool `json:"restartRequired"` +} diff --git a/starrshared/update.go b/starrshared/update.go new file mode 100644 index 00000000..ff613c8b --- /dev/null +++ b/starrshared/update.go @@ -0,0 +1,25 @@ +package starrshared + +import "time" + +// UpdateChanges is the change log embedded in Update. +type UpdateChanges struct { + New []string `json:"new,omitempty"` + Fixed []string `json:"fixed,omitempty"` +} + +// Update is one available or installed update from the /update endpoint. +type Update struct { + ID int `json:"id,omitempty"` + Version string `json:"version,omitempty"` + Branch string `json:"branch,omitempty"` + ReleaseDate time.Time `json:"releaseDate,omitzero"` + FileName string `json:"fileName,omitempty"` + URL string `json:"url,omitempty"` + Installed bool `json:"installed"` + InstalledOn time.Time `json:"installedOn,omitzero"` + Installable bool `json:"installable"` + Latest bool `json:"latest"` + Changes *UpdateChanges `json:"changes,omitempty"` + Hash string `json:"hash,omitempty"` +}