Add tag support to Sonarr/Radarr requests
This commit is contained in:
8
pvr.go
8
pvr.go
@@ -23,6 +23,7 @@ type PvrConfig struct {
|
|||||||
} `yaml:"options"`
|
} `yaml:"options"`
|
||||||
Filters PvrFilters `yaml:"filters"`
|
Filters PvrFilters `yaml:"filters"`
|
||||||
CacheDuration time.Duration `yaml:"cache_duration"`
|
CacheDuration time.Duration `yaml:"cache_duration"`
|
||||||
|
Tag string `yaml:"tag,omitempty"`
|
||||||
Verbosity string `yaml:"verbosity,omitempty"`
|
Verbosity string `yaml:"verbosity,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,6 +41,7 @@ type PvrOptions struct {
|
|||||||
|
|
||||||
AddMonitored bool
|
AddMonitored bool
|
||||||
SearchMissing bool
|
SearchMissing bool
|
||||||
|
Tag string
|
||||||
}
|
}
|
||||||
|
|
||||||
func BuildPvrOptions(opts ...PvrOption) (*PvrOptions, error) {
|
func BuildPvrOptions(opts ...PvrOption) (*PvrOptions, error) {
|
||||||
@@ -69,3 +71,9 @@ func WithSearchMissing(missing bool) PvrOption {
|
|||||||
opts.SearchMissing = missing
|
opts.SearchMissing = missing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func WithTag(tag string) PvrOption {
|
||||||
|
return func(opts *PvrOptions) {
|
||||||
|
opts.Tag = tag
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -148,6 +148,57 @@ func (c *Client) getExclusions() (map[int]exclusion, error) {
|
|||||||
return exclusions, nil
|
return exclusions, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Client) getOrCreateTag(tagName string) (int, error) {
|
||||||
|
// get all tags
|
||||||
|
resp, err := rek.Get(util.JoinURL(c.apiURL, "tag"), rek.Client(c.http), rek.Headers(c.apiHeaders))
|
||||||
|
if err != nil {
|
||||||
|
return 0, fmt.Errorf("request tags: %w", err)
|
||||||
|
}
|
||||||
|
defer resp.Body().Close()
|
||||||
|
|
||||||
|
// validate response
|
||||||
|
if resp.StatusCode() != 200 {
|
||||||
|
return 0, fmt.Errorf("validate tags response: %s", resp.Status())
|
||||||
|
}
|
||||||
|
|
||||||
|
// decode response
|
||||||
|
tags := new([]tag)
|
||||||
|
if err := json.NewDecoder(resp.Body()).Decode(tags); err != nil {
|
||||||
|
return 0, fmt.Errorf("decode tags response: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// find tag by name
|
||||||
|
for _, t := range *tags {
|
||||||
|
if strings.EqualFold(t.Label, tagName) {
|
||||||
|
return t.Id, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// tag not found, create it
|
||||||
|
createReq := tag{
|
||||||
|
Label: tagName,
|
||||||
|
}
|
||||||
|
createResp, err := rek.Post(util.JoinURL(c.apiURL, "tag"), rek.Client(c.http), rek.Headers(c.apiHeaders),
|
||||||
|
rek.Json(createReq))
|
||||||
|
if err != nil {
|
||||||
|
return 0, fmt.Errorf("request create tag: %w", err)
|
||||||
|
}
|
||||||
|
defer createResp.Body().Close()
|
||||||
|
|
||||||
|
// validate response
|
||||||
|
if createResp.StatusCode() != 200 && createResp.StatusCode() != 201 {
|
||||||
|
return 0, fmt.Errorf("validate create tag response: %s", createResp.Status())
|
||||||
|
}
|
||||||
|
|
||||||
|
// decode created tag
|
||||||
|
createdTag := new(tag)
|
||||||
|
if err := json.NewDecoder(createResp.Body()).Decode(createdTag); err != nil {
|
||||||
|
return 0, fmt.Errorf("decode create tag response: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return createdTag.Id, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Client) AddMediaItem(item *media.Item, opts ...nabarr.PvrOption) error {
|
func (c *Client) AddMediaItem(item *media.Item, opts ...nabarr.PvrOption) error {
|
||||||
// prepare options
|
// prepare options
|
||||||
o, err := nabarr.BuildPvrOptions(opts...)
|
o, err := nabarr.BuildPvrOptions(opts...)
|
||||||
@@ -155,6 +206,16 @@ func (c *Client) AddMediaItem(item *media.Item, opts ...nabarr.PvrOption) error
|
|||||||
return fmt.Errorf("build options: %v: %w", item.TmdbId, err)
|
return fmt.Errorf("build options: %v: %w", item.TmdbId, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// prepare tags
|
||||||
|
tags := []int{}
|
||||||
|
if o.Tag != "" {
|
||||||
|
tagId, err := c.getOrCreateTag(o.Tag)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("get or create tag %q: %w", o.Tag, err)
|
||||||
|
}
|
||||||
|
tags = []int{tagId}
|
||||||
|
}
|
||||||
|
|
||||||
// prepare request
|
// prepare request
|
||||||
req := addRequest{
|
req := addRequest{
|
||||||
Title: item.Title,
|
Title: item.Title,
|
||||||
@@ -162,6 +223,7 @@ func (c *Client) AddMediaItem(item *media.Item, opts ...nabarr.PvrOption) error
|
|||||||
Year: item.Year,
|
Year: item.Year,
|
||||||
QualityProfileId: c.qualityProfileId,
|
QualityProfileId: c.qualityProfileId,
|
||||||
Images: []string{},
|
Images: []string{},
|
||||||
|
Tags: tags,
|
||||||
Monitored: o.AddMonitored,
|
Monitored: o.AddMonitored,
|
||||||
RootFolderPath: c.rootFolder,
|
RootFolderPath: c.rootFolder,
|
||||||
MinimumAvailability: "released",
|
MinimumAvailability: "released",
|
||||||
|
|||||||
@@ -223,6 +223,9 @@ func (c *Client) queueProcessor(tail state.ShutdownTail) {
|
|||||||
nabarr.WithAddMonitored(c.addMonitored),
|
nabarr.WithAddMonitored(c.addMonitored),
|
||||||
nabarr.WithSearchMissing(c.searchMissing),
|
nabarr.WithSearchMissing(c.searchMissing),
|
||||||
}
|
}
|
||||||
|
if c.tag != "" {
|
||||||
|
opts = append(opts, nabarr.WithTag(c.tag))
|
||||||
|
}
|
||||||
|
|
||||||
if err := c.AddMediaItem(mediaItem, opts...); err != nil {
|
if err := c.AddMediaItem(mediaItem, opts...); err != nil {
|
||||||
c.log.Error().
|
c.log.Error().
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ type Client struct {
|
|||||||
// options
|
// options
|
||||||
searchMissing bool
|
searchMissing bool
|
||||||
addMonitored bool
|
addMonitored bool
|
||||||
|
tag string
|
||||||
|
|
||||||
apiURL string
|
apiURL string
|
||||||
apiHeaders map[string]string
|
apiHeaders map[string]string
|
||||||
@@ -77,6 +78,7 @@ func New(c nabarr.PvrConfig, mode string, m *media.Client, cc *cache.Client) (*C
|
|||||||
rootFolder: c.RootFolder,
|
rootFolder: c.RootFolder,
|
||||||
searchMissing: util.BoolOrDefault(c.Options.SearchMissing, true),
|
searchMissing: util.BoolOrDefault(c.Options.SearchMissing, true),
|
||||||
addMonitored: util.BoolOrDefault(c.Options.AddMonitored, true),
|
addMonitored: util.BoolOrDefault(c.Options.AddMonitored, true),
|
||||||
|
tag: c.Tag,
|
||||||
|
|
||||||
cache: cc,
|
cache: cc,
|
||||||
cacheTempDuration: c.CacheDuration,
|
cacheTempDuration: c.CacheDuration,
|
||||||
|
|||||||
@@ -9,6 +9,11 @@ type qualityProfile struct {
|
|||||||
Id int
|
Id int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type tag struct {
|
||||||
|
Id int `json:"id"`
|
||||||
|
Label string `json:"label"`
|
||||||
|
}
|
||||||
|
|
||||||
type exclusion struct {
|
type exclusion struct {
|
||||||
TmdbId int `json:"tmdbId"`
|
TmdbId int `json:"tmdbId"`
|
||||||
MovieTitle string `json:"movieTitle"`
|
MovieTitle string `json:"movieTitle"`
|
||||||
@@ -31,6 +36,7 @@ type addRequest struct {
|
|||||||
Year int `json:"year"`
|
Year int `json:"year"`
|
||||||
QualityProfileId int `json:"qualityProfileId"`
|
QualityProfileId int `json:"qualityProfileId"`
|
||||||
Images []string `json:"images"`
|
Images []string `json:"images"`
|
||||||
|
Tags []int `json:"tags"`
|
||||||
Monitored bool `json:"monitored"`
|
Monitored bool `json:"monitored"`
|
||||||
RootFolderPath string `json:"rootFolderPath"`
|
RootFolderPath string `json:"rootFolderPath"`
|
||||||
MinimumAvailability string `json:"minimumAvailability"`
|
MinimumAvailability string `json:"minimumAvailability"`
|
||||||
|
|||||||
@@ -183,6 +183,12 @@ func (c *Client) AddMediaItem(item *media.Item, opts ...nabarr.PvrOption) error
|
|||||||
return fmt.Errorf("converting tvdb id to int: %q", item.TvdbId)
|
return fmt.Errorf("converting tvdb id to int: %q", item.TvdbId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// prepare tags
|
||||||
|
tags := []string{}
|
||||||
|
if o.Tag != "" {
|
||||||
|
tags = []string{o.Tag}
|
||||||
|
}
|
||||||
|
|
||||||
req := addRequest{
|
req := addRequest{
|
||||||
Title: item.Title,
|
Title: item.Title,
|
||||||
TitleSlug: item.Slug,
|
TitleSlug: item.Slug,
|
||||||
@@ -190,7 +196,7 @@ func (c *Client) AddMediaItem(item *media.Item, opts ...nabarr.PvrOption) error
|
|||||||
QualityProfileId: c.qualityProfileId,
|
QualityProfileId: c.qualityProfileId,
|
||||||
LanguageProfileId: c.languageProfileId,
|
LanguageProfileId: c.languageProfileId,
|
||||||
Images: []string{},
|
Images: []string{},
|
||||||
Tags: []string{},
|
Tags: tags,
|
||||||
Monitored: o.AddMonitored,
|
Monitored: o.AddMonitored,
|
||||||
RootFolderPath: c.rootFolder,
|
RootFolderPath: c.rootFolder,
|
||||||
AddOptions: addOptions{
|
AddOptions: addOptions{
|
||||||
|
|||||||
@@ -229,6 +229,9 @@ func (c *Client) queueProcessor(tail state.ShutdownTail) {
|
|||||||
nabarr.WithAddMonitored(c.addMonitored),
|
nabarr.WithAddMonitored(c.addMonitored),
|
||||||
nabarr.WithSearchMissing(c.searchMissing),
|
nabarr.WithSearchMissing(c.searchMissing),
|
||||||
}
|
}
|
||||||
|
if c.tag != "" {
|
||||||
|
opts = append(opts, nabarr.WithTag(c.tag))
|
||||||
|
}
|
||||||
|
|
||||||
if err := c.AddMediaItem(mediaItem, opts...); err != nil {
|
if err := c.AddMediaItem(mediaItem, opts...); err != nil {
|
||||||
c.log.Error().
|
c.log.Error().
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ type Client struct {
|
|||||||
searchMissing bool
|
searchMissing bool
|
||||||
addMonitored bool
|
addMonitored bool
|
||||||
skipAnime bool
|
skipAnime bool
|
||||||
|
tag string
|
||||||
|
|
||||||
apiURL string
|
apiURL string
|
||||||
apiHeaders map[string]string
|
apiHeaders map[string]string
|
||||||
@@ -81,6 +82,7 @@ func New(c nabarr.PvrConfig, mode string, m *media.Client, cc *cache.Client) (*C
|
|||||||
searchMissing: util.BoolOrDefault(c.Options.SearchMissing, true),
|
searchMissing: util.BoolOrDefault(c.Options.SearchMissing, true),
|
||||||
addMonitored: util.BoolOrDefault(c.Options.AddMonitored, true),
|
addMonitored: util.BoolOrDefault(c.Options.AddMonitored, true),
|
||||||
skipAnime: util.BoolOrDefault(c.Options.SkipAnime, true),
|
skipAnime: util.BoolOrDefault(c.Options.SkipAnime, true),
|
||||||
|
tag: c.Tag,
|
||||||
|
|
||||||
cache: cc,
|
cache: cc,
|
||||||
cacheTempDuration: c.CacheDuration,
|
cacheTempDuration: c.CacheDuration,
|
||||||
|
|||||||
Reference in New Issue
Block a user