pvr: add options and support for anime (#17)
* pvr: begin adding options * pvr: add ability to configure add behaviour via config * pvr: add skip_anime * pvr: do not continue processing item if lookup failed or add to pvr failed
This commit is contained in:
48
README.md
48
README.md
@@ -53,9 +53,28 @@ media:
|
|||||||
client_id: trakt-client-id
|
client_id: trakt-client-id
|
||||||
omdb:
|
omdb:
|
||||||
api_key: omdb-api-key
|
api_key: omdb-api-key
|
||||||
|
tvdb:
|
||||||
|
api_key: tvdb-legacy-api-key
|
||||||
```
|
```
|
||||||
|
|
||||||
An omdb `api_key` can also be provided which will be used to supplement trakt data with additional information such as IMDb rating, Metascore rating and Rotten Tomatoes rating.
|
An omdb `api_key` can be provided which will be used to supplement trakt data with additional information such as:
|
||||||
|
|
||||||
|
- Metascore
|
||||||
|
- RottenTomatoes
|
||||||
|
- ImdbRating
|
||||||
|
- ImdbVotes
|
||||||
|
- Language
|
||||||
|
- Country
|
||||||
|
|
||||||
|
An tvdb `api_key` can be provided which will be used to supplement trakt data with additional information such as:
|
||||||
|
|
||||||
|
- Runtime
|
||||||
|
- Language
|
||||||
|
- Genre
|
||||||
|
- AirsDayOfWeek
|
||||||
|
- SiteRating
|
||||||
|
- SiteRatingCount
|
||||||
|
|
||||||
|
|
||||||
### PVR
|
### PVR
|
||||||
|
|
||||||
@@ -69,6 +88,10 @@ pvrs:
|
|||||||
api_key: sonarr-api-key
|
api_key: sonarr-api-key
|
||||||
quality_profile: WEBDL-1080p
|
quality_profile: WEBDL-1080p
|
||||||
root_folder: /mnt/unionfs/Media/TV
|
root_folder: /mnt/unionfs/Media/TV
|
||||||
|
options:
|
||||||
|
add_monitored: true
|
||||||
|
search_missing: true
|
||||||
|
skip_anime: true
|
||||||
filters:
|
filters:
|
||||||
ignores:
|
ignores:
|
||||||
- 'not (FeedTitle matches "(?i)S\\d\\d?E?\\d?\\d?")'
|
- 'not (FeedTitle matches "(?i)S\\d\\d?E?\\d?\\d?")'
|
||||||
@@ -92,6 +115,15 @@ pvrs:
|
|||||||
- 'TvdbId in ["248783"]'
|
- 'TvdbId in ["248783"]'
|
||||||
```
|
```
|
||||||
|
|
||||||
|
The following `options` can be set to override the default behaviour when adding content to a PVR (types: Sonarr & Radarr).
|
||||||
|
|
||||||
|
- `add_monitored` (default: `true`) - Add new content as monitored
|
||||||
|
- `search_missing` (default: `true`) - Add new content and search immediately
|
||||||
|
|
||||||
|
The following `options` can be set to skip adding content to a Sonarr PVR.
|
||||||
|
|
||||||
|
- `skip_anime` (default: `true`) - If the series is of the anime type, do not add it
|
||||||
|
|
||||||
### RSS
|
### RSS
|
||||||
|
|
||||||
The rss configuration section is where you will specify the RSS feeds that Nabarr will work with.
|
The rss configuration section is where you will specify the RSS feeds that Nabarr will work with.
|
||||||
@@ -122,6 +154,8 @@ media:
|
|||||||
client_id: trakt-client-id
|
client_id: trakt-client-id
|
||||||
omdb:
|
omdb:
|
||||||
api_key: omdb-api-key
|
api_key: omdb-api-key
|
||||||
|
tvdb:
|
||||||
|
api_key: tvdb-legacy-api-key
|
||||||
pvrs:
|
pvrs:
|
||||||
- name: sonarr
|
- name: sonarr
|
||||||
type: sonarr
|
type: sonarr
|
||||||
@@ -133,14 +167,17 @@ pvrs:
|
|||||||
ignores:
|
ignores:
|
||||||
- 'not (FeedTitle matches "(?i)S\\d\\d?E?\\d?\\d?")'
|
- 'not (FeedTitle matches "(?i)S\\d\\d?E?\\d?\\d?")'
|
||||||
- 'FeedTitle matches "(?i)\\d\\d\\d\\d\\s?[\\s\\.\\-]\\d\\d?\\s?[\\s\\.\\-]\\d\\d?"'
|
- 'FeedTitle matches "(?i)\\d\\d\\d\\d\\s?[\\s\\.\\-]\\d\\d?\\s?[\\s\\.\\-]\\d\\d?"'
|
||||||
- 'len(Languages) != 1 || "en" not in Languages'
|
- 'not (any(Country, {# in ["us", "gb", "au", "ca", "nz"]})) && not (any(["USA", "UK", "Australia", "Canada", "New Zealand"], {Omdb.Country == #}))'
|
||||||
|
- 'len(Languages) > 0 && not (any(Languages, {# in ["en", ""]}))'
|
||||||
|
- 'Omdb.Language != "" && Omdb.Language != "English"'
|
||||||
|
- 'Tvdb.Language != "" && Tvdb.Language != "en"'
|
||||||
|
- 'not (any(Languages, {# in ["en", ""]})) && Omdb.Language == "" && Tvdb.Language == ""'
|
||||||
- 'Runtime < 10 || Runtime > 70'
|
- 'Runtime < 10 || Runtime > 70'
|
||||||
- 'Network == ""'
|
- 'Network == ""'
|
||||||
- 'any (["Hallmark Movies"], {Network contains #})'
|
- 'any (["Hallmark Movies"], {Network contains #})'
|
||||||
- 'not (any(Country, {# in ["us", "gb", "au", "ca"]}))'
|
|
||||||
- 'Year < 2000'
|
- 'Year < 2000'
|
||||||
- 'Year < 2021 && Omdb.ImdbRating < 7.5'
|
- 'Year < 2021 && Omdb.ImdbRating < 7.5'
|
||||||
- 'AiredEpisodes > 200'
|
- 'AiredEpisodes > 100'
|
||||||
- 'Year > (Now().Year() + 1)'
|
- 'Year > (Now().Year() + 1)'
|
||||||
- 'any (["WWE", "AEW", "WWF", "NXT", "Live:", "Concert", "Musical", " Edition", "Wrestling"], {Title contains #})'
|
- 'any (["WWE", "AEW", "WWF", "NXT", "Live:", "Concert", "Musical", " Edition", "Wrestling"], {Title contains #})'
|
||||||
- 'len(Genres) == 0'
|
- 'len(Genres) == 0'
|
||||||
@@ -158,7 +195,8 @@ pvrs:
|
|||||||
root_folder: /mnt/unionfs/Media/Movies
|
root_folder: /mnt/unionfs/Media/Movies
|
||||||
filters:
|
filters:
|
||||||
ignores:
|
ignores:
|
||||||
- 'len(Languages) != 1 || "en" not in Languages'
|
- 'not (any(Country, {# in ["us", "gb", "au", "ca", "nz"]})) && not (any(["USA", "UK", "Australia", "Canada", "New Zealand"], {Omdb.Country == #}))'
|
||||||
|
- 'not (any(Languages, {# in ["en"]})) && Omdb.Language != "English"'
|
||||||
- 'Runtime < 60'
|
- 'Runtime < 60'
|
||||||
- 'len(Genres) == 0'
|
- 'len(Genres) == 0'
|
||||||
- '("music" in Genres || "documentary" in Genres)'
|
- '("music" in Genres || "documentary" in Genres)'
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import (
|
|||||||
type PVR interface {
|
type PVR interface {
|
||||||
Type() string
|
Type() string
|
||||||
GetFiltersHash() string
|
GetFiltersHash() string
|
||||||
AddMediaItem(*media.Item) error
|
AddMediaItem(*media.Item, ...nabarr.PvrOption) error
|
||||||
ShouldIgnore(*media.Item) (bool, string, error)
|
ShouldIgnore(*media.Item) (bool, string, error)
|
||||||
Start() state.State
|
Start() state.State
|
||||||
QueueFeedItem(*media.FeedItem)
|
QueueFeedItem(*media.FeedItem)
|
||||||
|
|||||||
53
pvr.go
53
pvr.go
@@ -1,6 +1,10 @@
|
|||||||
package nabarr
|
package nabarr
|
||||||
|
|
||||||
import "time"
|
import (
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
/* pvr config / filters */
|
||||||
|
|
||||||
type PvrConfig struct {
|
type PvrConfig struct {
|
||||||
Name string `yaml:"name"`
|
Name string `yaml:"name"`
|
||||||
@@ -9,6 +13,13 @@ type PvrConfig struct {
|
|||||||
ApiKey string `yaml:"api_key"`
|
ApiKey string `yaml:"api_key"`
|
||||||
QualityProfile string `yaml:"quality_profile"`
|
QualityProfile string `yaml:"quality_profile"`
|
||||||
RootFolder string `yaml:"root_folder"`
|
RootFolder string `yaml:"root_folder"`
|
||||||
|
Options struct {
|
||||||
|
// add options
|
||||||
|
AddMonitored *bool `yaml:"add_monitored"`
|
||||||
|
SearchMissing *bool `yaml:"search_missing"`
|
||||||
|
// skip objects
|
||||||
|
SkipAnime *bool `yaml:"skip_anime"`
|
||||||
|
} `yaml:"options"`
|
||||||
Filters PvrFilters `yaml:"filters"`
|
Filters PvrFilters `yaml:"filters"`
|
||||||
CacheDuration time.Duration `yaml:"cache_duration"`
|
CacheDuration time.Duration `yaml:"cache_duration"`
|
||||||
Verbosity string `yaml:"verbosity,omitempty"`
|
Verbosity string `yaml:"verbosity,omitempty"`
|
||||||
@@ -17,3 +28,43 @@ type PvrConfig struct {
|
|||||||
type PvrFilters struct {
|
type PvrFilters struct {
|
||||||
Ignores []string
|
Ignores []string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* pvr options */
|
||||||
|
|
||||||
|
type PvrOption func(options *PvrOptions)
|
||||||
|
|
||||||
|
type PvrOptions struct {
|
||||||
|
// the seriesType returned from the lookup before adding (sonarr)
|
||||||
|
LookupType string
|
||||||
|
|
||||||
|
AddMonitored bool
|
||||||
|
SearchMissing bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func BuildPvrOptions(opts ...PvrOption) (*PvrOptions, error) {
|
||||||
|
os := &PvrOptions{}
|
||||||
|
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(os)
|
||||||
|
}
|
||||||
|
|
||||||
|
return os, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithSeriesType(seriesType string) PvrOption {
|
||||||
|
return func(opts *PvrOptions) {
|
||||||
|
opts.LookupType = seriesType
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithAddMonitored(monitored bool) PvrOption {
|
||||||
|
return func(opts *PvrOptions) {
|
||||||
|
opts.AddMonitored = monitored
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithSearchMissing(missing bool) PvrOption {
|
||||||
|
return func(opts *PvrOptions) {
|
||||||
|
opts.SearchMissing = missing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/l3uddz/nabarr"
|
||||||
"github.com/l3uddz/nabarr/media"
|
"github.com/l3uddz/nabarr/media"
|
||||||
"github.com/l3uddz/nabarr/util"
|
"github.com/l3uddz/nabarr/util"
|
||||||
"github.com/lucperkins/rek"
|
"github.com/lucperkins/rek"
|
||||||
@@ -122,7 +123,13 @@ func (c *Client) lookupMediaItem(item *media.Item) (*lookupRequest, error) {
|
|||||||
return nil, fmt.Errorf("movie lookup %sId: %v: %w", mdType, mdId, ErrItemNotFound)
|
return nil, fmt.Errorf("movie lookup %sId: %v: %w", mdType, mdId, ErrItemNotFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) AddMediaItem(item *media.Item) error {
|
func (c *Client) AddMediaItem(item *media.Item, opts ...nabarr.PvrOption) error {
|
||||||
|
// prepare options
|
||||||
|
o, err := nabarr.BuildPvrOptions(opts...)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("build options: %v: %w", item.TmdbId, err)
|
||||||
|
}
|
||||||
|
|
||||||
// prepare request
|
// prepare request
|
||||||
req := addRequest{
|
req := addRequest{
|
||||||
Title: item.Title,
|
Title: item.Title,
|
||||||
@@ -130,11 +137,11 @@ func (c *Client) AddMediaItem(item *media.Item) error {
|
|||||||
Year: item.Year,
|
Year: item.Year,
|
||||||
QualityProfileId: c.qualityProfileId,
|
QualityProfileId: c.qualityProfileId,
|
||||||
Images: []string{},
|
Images: []string{},
|
||||||
Monitored: true,
|
Monitored: o.AddMonitored,
|
||||||
RootFolderPath: c.rootFolder,
|
RootFolderPath: c.rootFolder,
|
||||||
MinimumAvailability: "released",
|
MinimumAvailability: "released",
|
||||||
AddOptions: addOptions{
|
AddOptions: addOptions{
|
||||||
SearchForMovie: true,
|
SearchForMovie: o.SearchMissing,
|
||||||
IgnoreEpisodesWithFiles: false,
|
IgnoreEpisodesWithFiles: false,
|
||||||
IgnoreEpisodesWithoutFiles: false,
|
IgnoreEpisodesWithoutFiles: false,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package radarr
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/l3uddz/nabarr"
|
||||||
"github.com/l3uddz/nabarr/media"
|
"github.com/l3uddz/nabarr/media"
|
||||||
"github.com/lefelys/state"
|
"github.com/lefelys/state"
|
||||||
)
|
)
|
||||||
@@ -144,6 +145,7 @@ func (c *Client) queueProcessor(tail state.ShutdownTail) {
|
|||||||
Str("feed_imdb_id", feedItem.ImdbId).
|
Str("feed_imdb_id", feedItem.ImdbId).
|
||||||
Str("feed_name", feedItem.Feed).
|
Str("feed_name", feedItem.Feed).
|
||||||
Msg("Failed finding item via pvr lookup")
|
Msg("Failed finding item via pvr lookup")
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.Id > 0 {
|
if s.Id > 0 {
|
||||||
@@ -184,7 +186,6 @@ func (c *Client) queueProcessor(tail state.ShutdownTail) {
|
|||||||
|
|
||||||
if c.testMode {
|
if c.testMode {
|
||||||
c.log.Info().
|
c.log.Info().
|
||||||
Err(err).
|
|
||||||
Str("trakt_title", mediaItem.Title).
|
Str("trakt_title", mediaItem.Title).
|
||||||
Str("trakt_imdb_id", mediaItem.ImdbId).
|
Str("trakt_imdb_id", mediaItem.ImdbId).
|
||||||
Str("trakt_tmdb_id", mediaItem.TmdbId).
|
Str("trakt_tmdb_id", mediaItem.TmdbId).
|
||||||
@@ -194,7 +195,12 @@ func (c *Client) queueProcessor(tail state.ShutdownTail) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.AddMediaItem(mediaItem); err != nil {
|
opts := []nabarr.PvrOption{
|
||||||
|
nabarr.WithAddMonitored(c.addMonitored),
|
||||||
|
nabarr.WithSearchMissing(c.searchMissing),
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.AddMediaItem(mediaItem, opts...); err != nil {
|
||||||
c.log.Error().
|
c.log.Error().
|
||||||
Err(err).
|
Err(err).
|
||||||
Str("feed_title", mediaItem.FeedTitle).
|
Str("feed_title", mediaItem.FeedTitle).
|
||||||
@@ -204,6 +210,7 @@ func (c *Client) queueProcessor(tail state.ShutdownTail) {
|
|||||||
Int("trakt_year", mediaItem.Year).
|
Int("trakt_year", mediaItem.Year).
|
||||||
Str("feed_name", feedItem.Feed).
|
Str("feed_name", feedItem.Feed).
|
||||||
Msg("Failed adding item to pvr")
|
Msg("Failed adding item to pvr")
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// add item to perm cache (item was added to pvr)
|
// add item to perm cache (item was added to pvr)
|
||||||
@@ -216,7 +223,6 @@ func (c *Client) queueProcessor(tail state.ShutdownTail) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
c.log.Info().
|
c.log.Info().
|
||||||
Err(err).
|
|
||||||
Str("trakt_title", mediaItem.Title).
|
Str("trakt_title", mediaItem.Title).
|
||||||
Str("trakt_imdb_id", mediaItem.ImdbId).
|
Str("trakt_imdb_id", mediaItem.ImdbId).
|
||||||
Str("trakt_tmdb_id", mediaItem.TmdbId).
|
Str("trakt_tmdb_id", mediaItem.TmdbId).
|
||||||
|
|||||||
@@ -20,6 +20,10 @@ type Client struct {
|
|||||||
rootFolder string
|
rootFolder string
|
||||||
qualityProfileId int
|
qualityProfileId int
|
||||||
|
|
||||||
|
// options
|
||||||
|
searchMissing bool
|
||||||
|
addMonitored bool
|
||||||
|
|
||||||
apiURL string
|
apiURL string
|
||||||
apiHeaders map[string]string
|
apiHeaders map[string]string
|
||||||
apiTimeout time.Duration
|
apiTimeout time.Duration
|
||||||
@@ -66,6 +70,8 @@ func New(c nabarr.PvrConfig, mode string, m *media.Client, cc *cache.Client) (*C
|
|||||||
testMode: strings.EqualFold(mode, "test"),
|
testMode: strings.EqualFold(mode, "test"),
|
||||||
|
|
||||||
rootFolder: c.RootFolder,
|
rootFolder: c.RootFolder,
|
||||||
|
searchMissing: util.BoolOrDefault(c.Options.SearchMissing, true),
|
||||||
|
addMonitored: util.BoolOrDefault(c.Options.AddMonitored, true),
|
||||||
|
|
||||||
cache: cc,
|
cache: cc,
|
||||||
cacheTempDuration: c.CacheDuration,
|
cacheTempDuration: c.CacheDuration,
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/l3uddz/nabarr"
|
||||||
"github.com/l3uddz/nabarr/media"
|
"github.com/l3uddz/nabarr/media"
|
||||||
"github.com/l3uddz/nabarr/util"
|
"github.com/l3uddz/nabarr/util"
|
||||||
"github.com/lucperkins/rek"
|
"github.com/lucperkins/rek"
|
||||||
@@ -105,7 +106,13 @@ func (c *Client) lookupMediaItem(item *media.Item) (*lookupRequest, error) {
|
|||||||
return nil, fmt.Errorf("series lookup tvdbId: %v: %w", item.TvdbId, ErrItemNotFound)
|
return nil, fmt.Errorf("series lookup tvdbId: %v: %w", item.TvdbId, ErrItemNotFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) AddMediaItem(item *media.Item) error {
|
func (c *Client) AddMediaItem(item *media.Item, opts ...nabarr.PvrOption) error {
|
||||||
|
// prepare options
|
||||||
|
o, err := nabarr.BuildPvrOptions(opts...)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("build options: %v: %w", item.TvdbId, err)
|
||||||
|
}
|
||||||
|
|
||||||
// prepare request
|
// prepare request
|
||||||
tvdbId, err := strconv.Atoi(item.TvdbId)
|
tvdbId, err := strconv.Atoi(item.TvdbId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -119,15 +126,15 @@ func (c *Client) AddMediaItem(item *media.Item) error {
|
|||||||
QualityProfileId: c.qualityProfileId,
|
QualityProfileId: c.qualityProfileId,
|
||||||
Images: []string{},
|
Images: []string{},
|
||||||
Tags: []string{},
|
Tags: []string{},
|
||||||
Monitored: true,
|
Monitored: o.AddMonitored,
|
||||||
RootFolderPath: c.rootFolder,
|
RootFolderPath: c.rootFolder,
|
||||||
AddOptions: addOptions{
|
AddOptions: addOptions{
|
||||||
SearchForMissingEpisodes: true,
|
SearchForMissingEpisodes: o.SearchMissing,
|
||||||
IgnoreEpisodesWithFiles: false,
|
IgnoreEpisodesWithFiles: false,
|
||||||
IgnoreEpisodesWithoutFiles: false,
|
IgnoreEpisodesWithoutFiles: false,
|
||||||
},
|
},
|
||||||
Seasons: []string{},
|
Seasons: []string{},
|
||||||
SeriesType: "standard",
|
SeriesType: util.StringOrDefault(o.LookupType, "standard"),
|
||||||
SeasonFolder: true,
|
SeasonFolder: true,
|
||||||
TvdbId: tvdbId,
|
TvdbId: tvdbId,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,8 +3,11 @@ package sonarr
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/l3uddz/nabarr"
|
||||||
"github.com/l3uddz/nabarr/media"
|
"github.com/l3uddz/nabarr/media"
|
||||||
|
"github.com/l3uddz/nabarr/util"
|
||||||
"github.com/lefelys/state"
|
"github.com/lefelys/state"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *Client) QueueFeedItem(item *media.FeedItem) {
|
func (c *Client) QueueFeedItem(item *media.FeedItem) {
|
||||||
@@ -134,6 +137,7 @@ func (c *Client) queueProcessor(tail state.ShutdownTail) {
|
|||||||
Str("feed_tvdb_id", feedItem.TvdbId).
|
Str("feed_tvdb_id", feedItem.TvdbId).
|
||||||
Str("feed_name", feedItem.Feed).
|
Str("feed_name", feedItem.Feed).
|
||||||
Msg("Failed finding item via pvr lookup")
|
Msg("Failed finding item via pvr lookup")
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.Id > 0 {
|
if s.Id > 0 {
|
||||||
@@ -156,6 +160,23 @@ func (c *Client) queueProcessor(tail state.ShutdownTail) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// set appropriate series type
|
||||||
|
switch {
|
||||||
|
case util.StringSliceContains(mediaItem.Genres, "anime"), util.StringSliceContains(mediaItem.Tvdb.Genre, "anime"):
|
||||||
|
s.Type = "anime"
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if item should be skipped (skip options)
|
||||||
|
if c.skipAnime && strings.EqualFold(s.Type, "anime") {
|
||||||
|
c.log.Debug().
|
||||||
|
Str("trakt_title", mediaItem.Title).
|
||||||
|
Str("trakt_tvdb_id", mediaItem.TvdbId).
|
||||||
|
Int("trakt_year", mediaItem.Year).
|
||||||
|
Str("feed_name", feedItem.Feed).
|
||||||
|
Msg("Skipping item (skip_anime enabled)")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
// add item to pvr
|
// add item to pvr
|
||||||
c.log.Debug().
|
c.log.Debug().
|
||||||
Str("feed_title", mediaItem.FeedTitle).
|
Str("feed_title", mediaItem.FeedTitle).
|
||||||
@@ -172,7 +193,6 @@ func (c *Client) queueProcessor(tail state.ShutdownTail) {
|
|||||||
|
|
||||||
if c.testMode {
|
if c.testMode {
|
||||||
c.log.Info().
|
c.log.Info().
|
||||||
Err(err).
|
|
||||||
Str("trakt_title", mediaItem.Title).
|
Str("trakt_title", mediaItem.Title).
|
||||||
Str("trakt_tvdb_id", mediaItem.TvdbId).
|
Str("trakt_tvdb_id", mediaItem.TvdbId).
|
||||||
Int("trakt_year", mediaItem.Year).
|
Int("trakt_year", mediaItem.Year).
|
||||||
@@ -181,7 +201,13 @@ func (c *Client) queueProcessor(tail state.ShutdownTail) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.AddMediaItem(mediaItem); err != nil {
|
opts := []nabarr.PvrOption{
|
||||||
|
nabarr.WithSeriesType(s.Type),
|
||||||
|
nabarr.WithAddMonitored(c.addMonitored),
|
||||||
|
nabarr.WithSearchMissing(c.searchMissing),
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.AddMediaItem(mediaItem, opts...); err != nil {
|
||||||
c.log.Error().
|
c.log.Error().
|
||||||
Err(err).
|
Err(err).
|
||||||
Str("feed_title", mediaItem.FeedTitle).
|
Str("feed_title", mediaItem.FeedTitle).
|
||||||
@@ -190,6 +216,7 @@ func (c *Client) queueProcessor(tail state.ShutdownTail) {
|
|||||||
Int("trakt_year", mediaItem.Year).
|
Int("trakt_year", mediaItem.Year).
|
||||||
Str("feed_name", feedItem.Feed).
|
Str("feed_name", feedItem.Feed).
|
||||||
Msg("Failed adding item to pvr")
|
Msg("Failed adding item to pvr")
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// add item to perm cache (item was added to pvr)
|
// add item to perm cache (item was added to pvr)
|
||||||
@@ -202,7 +229,6 @@ func (c *Client) queueProcessor(tail state.ShutdownTail) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
c.log.Info().
|
c.log.Info().
|
||||||
Err(err).
|
|
||||||
Str("trakt_title", mediaItem.Title).
|
Str("trakt_title", mediaItem.Title).
|
||||||
Str("trakt_tvdb_id", mediaItem.TvdbId).
|
Str("trakt_tvdb_id", mediaItem.TvdbId).
|
||||||
Int("trakt_year", mediaItem.Year).
|
Int("trakt_year", mediaItem.Year).
|
||||||
|
|||||||
@@ -20,6 +20,11 @@ type Client struct {
|
|||||||
rootFolder string
|
rootFolder string
|
||||||
qualityProfileId int
|
qualityProfileId int
|
||||||
|
|
||||||
|
// options
|
||||||
|
searchMissing bool
|
||||||
|
addMonitored bool
|
||||||
|
skipAnime bool
|
||||||
|
|
||||||
apiURL string
|
apiURL string
|
||||||
apiHeaders map[string]string
|
apiHeaders map[string]string
|
||||||
apiTimeout time.Duration
|
apiTimeout time.Duration
|
||||||
@@ -67,6 +72,10 @@ 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),
|
||||||
|
addMonitored: util.BoolOrDefault(c.Options.AddMonitored, true),
|
||||||
|
skipAnime: util.BoolOrDefault(c.Options.SkipAnime, true),
|
||||||
|
|
||||||
cache: cc,
|
cache: cc,
|
||||||
cacheTempDuration: c.CacheDuration,
|
cacheTempDuration: c.CacheDuration,
|
||||||
cacheFiltersHash: util.AsSHA256(c.Filters),
|
cacheFiltersHash: util.AsSHA256(c.Filters),
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ type lookupRequest struct {
|
|||||||
TitleSlug string `json:"titleSlug"`
|
TitleSlug string `json:"titleSlug"`
|
||||||
Year int `json:"year,omitempty"`
|
Year int `json:"year,omitempty"`
|
||||||
TvdbId int `json:"tvdbId"`
|
TvdbId int `json:"tvdbId"`
|
||||||
|
Type string `json:"seriesType"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type addRequest struct {
|
type addRequest struct {
|
||||||
|
|||||||
@@ -20,3 +20,18 @@ func Atof64(val string, defaultVal float64) float64 {
|
|||||||
}
|
}
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func StringOrDefault(val string, defaultVal string) string {
|
||||||
|
if val == "" {
|
||||||
|
return defaultVal
|
||||||
|
}
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
|
||||||
|
func BoolOrDefault(val *bool, defaultVal bool) bool {
|
||||||
|
if val == nil {
|
||||||
|
return defaultVal
|
||||||
|
}
|
||||||
|
|
||||||
|
return *val
|
||||||
|
}
|
||||||
|
|||||||
@@ -81,3 +81,39 @@ func TestAtoi(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestBoolOrDefault(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
val *bool
|
||||||
|
defaultVal bool
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
want bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "expect default",
|
||||||
|
args: args{
|
||||||
|
val: nil,
|
||||||
|
defaultVal: true,
|
||||||
|
},
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "expect value",
|
||||||
|
args: args{
|
||||||
|
val: new(bool),
|
||||||
|
defaultVal: true,
|
||||||
|
},
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
if got := BoolOrDefault(tt.args.val, tt.args.defaultVal); got != tt.want {
|
||||||
|
t.Errorf("BoolOrDefault() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
12
util/slice.go
Normal file
12
util/slice.go
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
package util
|
||||||
|
|
||||||
|
import "strings"
|
||||||
|
|
||||||
|
func StringSliceContains(slice []string, val string) bool {
|
||||||
|
for _, s := range slice {
|
||||||
|
if strings.EqualFold(s, val) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
39
util/slice_test.go
Normal file
39
util/slice_test.go
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
package util
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestStringSliceContains(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
slice []string
|
||||||
|
val string
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
want bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "expect true",
|
||||||
|
args: args{
|
||||||
|
slice: []string{"tes", "Test"},
|
||||||
|
val: "test",
|
||||||
|
},
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "expect false",
|
||||||
|
args: args{
|
||||||
|
slice: []string{"tes", "Test"},
|
||||||
|
val: "testing",
|
||||||
|
},
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
if got := StringSliceContains(tt.args.slice, tt.args.val); got != tt.want {
|
||||||
|
t.Errorf("StringSliceContains() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user