golift.io/starr@v1.0.0/sonarr/series.go (about)

     1  package sonarr
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"encoding/json"
     7  	"fmt"
     8  	"net/url"
     9  	"path"
    10  	"time"
    11  
    12  	"golift.io/starr"
    13  )
    14  
    15  // Define Base Path for Series calls.
    16  const bpSeries = APIver + "/series"
    17  
    18  // AddSeriesInput is the input for /api/v3/series endpoint.
    19  type AddSeriesInput struct {
    20  	Monitored         bool           `json:"monitored"`
    21  	SeasonFolder      bool           `json:"seasonFolder,omitempty"`
    22  	UseSceneNumbering bool           `json:"useSceneNumbering,omitempty"`
    23  	ID                int64          `json:"id,omitempty"`
    24  	LanguageProfileID int64          `json:"languageProfileId,omitempty"`
    25  	QualityProfileID  int64          `json:"qualityProfileId,omitempty"`
    26  	TvdbID            int64          `json:"tvdbId,omitempty"`
    27  	ImdbID            string         `json:"imdbId,omitempty"`
    28  	TvMazeID          int64          `json:"tvMazeId,omitempty"`
    29  	TvRageID          int64          `json:"tvRageId,omitempty"`
    30  	Path              string         `json:"path,omitempty"`
    31  	SeriesType        string         `json:"seriesType,omitempty"`
    32  	Title             string         `json:"title,omitempty"`
    33  	TitleSlug         string         `json:"titleSlug,omitempty"`
    34  	RootFolderPath    string         `json:"rootFolderPath,omitempty"`
    35  	Tags              []int          `json:"tags,omitempty"`
    36  	Seasons           []*Season      `json:"seasons,omitempty"`
    37  	Images            []*starr.Image `json:"images,omitempty"`
    38  	// to be used only on POST, not for PUT
    39  	AddOptions *AddSeriesOptions `json:"addOptions,omitempty"`
    40  }
    41  
    42  // Series is the output of /api/v3/series endpoint.
    43  type Series struct {
    44  	Ended             bool              `json:"ended,omitempty"`
    45  	Monitored         bool              `json:"monitored"`
    46  	SeasonFolder      bool              `json:"seasonFolder,omitempty"`
    47  	UseSceneNumbering bool              `json:"useSceneNumbering,omitempty"`
    48  	Runtime           int               `json:"runtime,omitempty"`
    49  	Year              int               `json:"year,omitempty"`
    50  	ID                int64             `json:"id,omitempty"`
    51  	LanguageProfileID int64             `json:"languageProfileId,omitempty"`
    52  	QualityProfileID  int64             `json:"qualityProfileId,omitempty"`
    53  	TvdbID            int64             `json:"tvdbId,omitempty"`
    54  	TvMazeID          int64             `json:"tvMazeId,omitempty"`
    55  	TvRageID          int64             `json:"tvRageId,omitempty"`
    56  	AirTime           string            `json:"airTime,omitempty"`
    57  	Certification     string            `json:"certification,omitempty"`
    58  	CleanTitle        string            `json:"cleanTitle,omitempty"`
    59  	ImdbID            string            `json:"imdbId,omitempty"`
    60  	Network           string            `json:"network,omitempty"`
    61  	Overview          string            `json:"overview,omitempty"`
    62  	Path              string            `json:"path,omitempty"`
    63  	SeriesType        string            `json:"seriesType,omitempty"`
    64  	SortTitle         string            `json:"sortTitle,omitempty"`
    65  	Status            string            `json:"status,omitempty"`
    66  	Title             string            `json:"title,omitempty"`
    67  	TitleSlug         string            `json:"titleSlug,omitempty"`
    68  	RootFolderPath    string            `json:"rootFolderPath,omitempty"`
    69  	Added             time.Time         `json:"added,omitempty"`
    70  	FirstAired        time.Time         `json:"firstAired,omitempty"`
    71  	NextAiring        time.Time         `json:"nextAiring,omitempty"`
    72  	PreviousAiring    time.Time         `json:"previousAiring,omitempty"`
    73  	Ratings           *starr.Ratings    `json:"ratings,omitempty"`
    74  	Statistics        *Statistics       `json:"statistics,omitempty"`
    75  	Tags              []int             `json:"tags,omitempty"`
    76  	Genres            []string          `json:"genres,omitempty"`
    77  	AlternateTitles   []*AlternateTitle `json:"alternateTitles,omitempty"`
    78  	Seasons           []*Season         `json:"seasons,omitempty"`
    79  	Images            []*starr.Image    `json:"images,omitempty"`
    80  }
    81  
    82  // AddSeriesOptions is part of AddSeriesInput.
    83  type AddSeriesOptions struct {
    84  	SearchForMissingEpisodes     bool `json:"searchForMissingEpisodes"`
    85  	SearchForCutoffUnmetEpisodes bool `json:"searchForCutoffUnmetEpisodes,omitempty"`
    86  	IgnoreEpisodesWithFiles      bool `json:"ignoreEpisodesWithFiles,omitempty"`
    87  	IgnoreEpisodesWithoutFiles   bool `json:"ignoreEpisodesWithoutFiles,omitempty"`
    88  }
    89  
    90  // AlternateTitle is part of a AddSeriesInput.
    91  type AlternateTitle struct {
    92  	SeasonNumber int    `json:"seasonNumber"`
    93  	Title        string `json:"title"`
    94  }
    95  
    96  // Season is part of AddSeriesInput and Queue and used in a few places.
    97  type Season struct {
    98  	Monitored    bool        `json:"monitored"`
    99  	SeasonNumber int         `json:"seasonNumber"`
   100  	Statistics   *Statistics `json:"statistics,omitempty"`
   101  }
   102  
   103  // Statistics is part of AddSeriesInput and Queue.
   104  type Statistics struct {
   105  	SeasonCount       int       `json:"seasonCount"`
   106  	EpisodeFileCount  int       `json:"episodeFileCount"`
   107  	EpisodeCount      int       `json:"episodeCount"`
   108  	TotalEpisodeCount int       `json:"totalEpisodeCount"`
   109  	SizeOnDisk        int64     `json:"sizeOnDisk"`
   110  	PercentOfEpisodes float64   `json:"percentOfEpisodes"`
   111  	PreviousAiring    time.Time `json:"previousAiring"`
   112  }
   113  
   114  // GetAllSeries returns all configured series.
   115  // This may not deal well with pagination atm, let us know?
   116  func (s *Sonarr) GetAllSeries() ([]*Series, error) {
   117  	return s.GetAllSeriesContext(context.Background())
   118  }
   119  
   120  // GetAllSeriesContext returns all configured series.
   121  // This may not deal well with pagination atm, let us know?
   122  func (s *Sonarr) GetAllSeriesContext(ctx context.Context) ([]*Series, error) {
   123  	return s.GetSeriesContext(ctx, 0)
   124  }
   125  
   126  // GetSeries locates and returns a series by tvdbID. If tvdbID is 0, returns all series.
   127  func (s *Sonarr) GetSeries(tvdbID int64) ([]*Series, error) {
   128  	return s.GetSeriesContext(context.Background(), tvdbID)
   129  }
   130  
   131  // GetSeriesContext locates and returns a series by tvdbID. If tvdbID is 0, returns all series.
   132  func (s *Sonarr) GetSeriesContext(ctx context.Context, tvdbID int64) ([]*Series, error) {
   133  	var output []*Series
   134  
   135  	req := starr.Request{URI: bpSeries, Query: make(url.Values)}
   136  	if tvdbID != 0 {
   137  		req.Query.Add("tvdbId", fmt.Sprint(tvdbID))
   138  	}
   139  
   140  	if err := s.GetInto(ctx, req, &output); err != nil {
   141  		return nil, fmt.Errorf("api.Get(%s): %w", &req, err)
   142  	}
   143  
   144  	return output, nil
   145  }
   146  
   147  // UpdateSeries updates a series in place.
   148  func (s *Sonarr) UpdateSeries(series *AddSeriesInput, moveFiles bool) (*Series, error) {
   149  	return s.UpdateSeriesContext(context.Background(), series, moveFiles)
   150  }
   151  
   152  // UpdateSeriesContext updates a series in place.
   153  func (s *Sonarr) UpdateSeriesContext(ctx context.Context, series *AddSeriesInput, moveFiles bool) (*Series, error) {
   154  	var body bytes.Buffer
   155  	if err := json.NewEncoder(&body).Encode(series); err != nil {
   156  		return nil, fmt.Errorf("json.Marshal(%s): %w", bpSeries, err)
   157  	}
   158  
   159  	var output Series
   160  
   161  	req := starr.Request{
   162  		URI:   path.Join(bpSeries, fmt.Sprint(series.ID)),
   163  		Query: make(url.Values),
   164  		Body:  &body,
   165  	}
   166  	req.Query.Add("moveFiles", fmt.Sprint(moveFiles))
   167  
   168  	if err := s.PutInto(ctx, req, &output); err != nil {
   169  		return nil, fmt.Errorf("api.Put(%s): %w", &req, err)
   170  	}
   171  
   172  	return &output, nil
   173  }
   174  
   175  // AddSeries adds a new series to Sonarr.
   176  func (s *Sonarr) AddSeries(series *AddSeriesInput) (*Series, error) {
   177  	return s.AddSeriesContext(context.Background(), series)
   178  }
   179  
   180  // AddSeriesContext adds a new series to Sonarr.
   181  func (s *Sonarr) AddSeriesContext(ctx context.Context, series *AddSeriesInput) (*Series, error) {
   182  	var body bytes.Buffer
   183  	if err := json.NewEncoder(&body).Encode(series); err != nil {
   184  		return nil, fmt.Errorf("json.Marshal(%s): %w", bpSeries, err)
   185  	}
   186  
   187  	var output Series
   188  
   189  	req := starr.Request{URI: bpSeries, Query: make(url.Values), Body: &body}
   190  	if err := s.PostInto(ctx, req, &output); err != nil {
   191  		return nil, fmt.Errorf("api.Post(%s): %w", &req, err)
   192  	}
   193  
   194  	return &output, nil
   195  }
   196  
   197  // GetSeriesByID locates and returns a series by DB [series] ID.
   198  func (s *Sonarr) GetSeriesByID(seriesID int64) (*Series, error) {
   199  	return s.GetSeriesByIDContext(context.Background(), seriesID)
   200  }
   201  
   202  // GetSeriesByIDContext locates and returns a series by DB [series] ID.
   203  func (s *Sonarr) GetSeriesByIDContext(ctx context.Context, seriesID int64) (*Series, error) {
   204  	var output Series
   205  
   206  	req := starr.Request{URI: path.Join(bpSeries, fmt.Sprint(seriesID))}
   207  	if err := s.GetInto(ctx, req, &output); err != nil {
   208  		return nil, fmt.Errorf("api.Get(%s): %w", &req, err)
   209  	}
   210  
   211  	return &output, nil
   212  }
   213  
   214  // GetSeriesLookup searches for a series [in Servarr] using a search term or a tvdbid.
   215  // Provide a search term or a tvdbid. If you provide both, tvdbID is used.
   216  func (s *Sonarr) GetSeriesLookup(term string, tvdbID int64) ([]*Series, error) {
   217  	return s.GetSeriesLookupContext(context.Background(), term, tvdbID)
   218  }
   219  
   220  // GetSeriesLookupContext searches for a series [in Servarr] using a search term or a tvdbid.
   221  // Provide a search term or a tvdbid. If you provide both, tvdbID is used.
   222  func (s *Sonarr) GetSeriesLookupContext(ctx context.Context, term string, tvdbID int64) ([]*Series, error) {
   223  	var output []*Series
   224  
   225  	req := starr.Request{URI: path.Join(bpSeries, "lookup"), Query: make(url.Values)}
   226  	if tvdbID > 0 {
   227  		req.Query.Add("term", "tvdbid:"+fmt.Sprint(tvdbID))
   228  	} else {
   229  		req.Query.Add("term", term)
   230  	}
   231  
   232  	if err := s.GetInto(ctx, req, &output); err != nil {
   233  		return nil, fmt.Errorf("api.Get(%s): %w", &req, err)
   234  	}
   235  
   236  	return output, nil
   237  }
   238  
   239  // Lookup will search for series matching the specified search term.
   240  // Searches for new shows on TheTVDB.com utilizing sonarr.tv's caching and augmentation proxy.
   241  func (s *Sonarr) Lookup(term string) ([]*Series, error) {
   242  	return s.LookupContext(context.Background(), term)
   243  }
   244  
   245  // Lookup will search for series matching the specified search term.
   246  // Searches for new shows on TheTVDB.com utilizing sonarr.tv's caching and augmentation proxy.
   247  func (s *Sonarr) LookupContext(ctx context.Context, term string) ([]*Series, error) {
   248  	return s.GetSeriesLookupContext(ctx, term, 0)
   249  }
   250  
   251  // DeleteSeries removes a single Series.
   252  // deleteFiles flag defines the deleteFiles query parameter.
   253  // importExclude defines the addImportListExclusion query parameter.
   254  func (s *Sonarr) DeleteSeries(seriesID int, deleteFiles bool, importExclude bool) error {
   255  	return s.DeleteSeriesContext(context.Background(), seriesID, deleteFiles, importExclude)
   256  }
   257  
   258  // DeleteSeries removes a single Series.
   259  // deleteFiles flag defines the deleteFiles query parameter.
   260  // importExclude defines the addImportListExclusion query parameter.
   261  func (s *Sonarr) DeleteSeriesContext(ctx context.Context, seriesID int, deleteFiles bool, importExclude bool) error {
   262  	req := starr.Request{URI: path.Join(bpSeries, fmt.Sprint(seriesID)), Query: make(url.Values)}
   263  	req.Query.Add("deleteFiles", fmt.Sprint(deleteFiles))
   264  	req.Query.Add("addImportListExclusion", fmt.Sprint(importExclude))
   265  
   266  	if err := s.DeleteAny(ctx, req); err != nil {
   267  		return fmt.Errorf("api.Delete(%s): %w", &req, err)
   268  	}
   269  
   270  	return nil
   271  }
   272  
   273  // DeleteSeriesDefault defines the behaviour to set deleteFiles to true and addImportListExclusion to false.
   274  func (s *Sonarr) DeleteSeriesDefault(seriesID int) error {
   275  	return s.DeleteSeriesContext(context.Background(), seriesID, true, false)
   276  }