Documentation
¶
Index ¶
Constants ¶
This section is empty.
Variables ¶
var ErrNoEligibleRelease = errors.New("rss: no eligible release for movie")
ErrNoEligibleRelease is returned by SearchOne when no indexer result passes the quality filter. last_search_at is still bumped so the cooldown counter advances.
Functions ¶
This section is empty.
Types ¶
type Downloader ¶
type Downloader interface {
Grab(
ctx context.Context,
result indexer.SearchResult,
movieID uint32,
) (*ent.DownloadRecord, error)
}
Downloader is the subset of download.Manager that rss.MissingSearcher needs.
type EligibleEpisodeLister ¶ added in v1.2.0
type EligibleEpisodeLister interface {
ListEligibleEpisodesForSync(
ctx context.Context,
maxGrabFailures uint8,
notSearchedSince time.Time,
airedBefore time.Time,
) ([]*ent.TVShow, error)
SetEpisodeStatus(ctx context.Context, id uint32, status episode.Status) error
SetEpisodeLastSearchAt(ctx context.Context, id uint32, when time.Time) error
IncrementEpisodeGrabFailures(ctx context.Context, id uint32) error
ResetEpisodeGrabFailures(ctx context.Context, id uint32) error
}
EligibleEpisodeLister is the subset of db.Store that rss.EpisodeMissingSearcher needs.
type EpisodeGrabber ¶
type EpisodeGrabber interface {
GrabEpisode(
ctx context.Context,
result indexer.SearchResult,
episodeID uint32,
) (*ent.DownloadRecord, error)
}
EpisodeGrabber is the subset of download.Downloader that rss.EpisodeMissingSearcher needs.
type EpisodeMissingSearcher ¶
type EpisodeMissingSearcher struct {
// contains filtered or unexported fields
}
EpisodeMissingSearcher scans wanted episodes, searches indexers, and grabs the best matching release per season. When a whole season is wanted it prefers a single season pack over per-episode grabs.
func NewEpisodeMissingSearcher ¶
func NewEpisodeMissingSearcher( store EligibleEpisodeLister, indexers TVIndexerSearcher, downloads EpisodeGrabber, ) *EpisodeMissingSearcher
func (*EpisodeMissingSearcher) Run ¶
func (s *EpisodeMissingSearcher) Run(ctx context.Context) error
Run performs one pass over every show with searchable episodes. Per-season errors are logged and never abort the pass; only a failure to list eligible shows is returned. Satisfies the MissingSearchRunner contract used by jobs.
func (*EpisodeMissingSearcher) SearchShow ¶
func (s *EpisodeMissingSearcher) SearchShow( ctx context.Context, showID uint32, ) error
SearchShow runs one search-and-grab pass scoped to a single series, so a show with nothing searchable is a no-op. Powers POST /series/{id}/search. A user asked for this pass, so the operator throttles are waived — matching the movie twin, where SearchMovieNow calls SearchOne directly instead of going through the eligibility query. The hard guards still apply.
type FeedRunner ¶
FeedRunner is the consumer-facing surface for triggering one feed scan. jobs.RSSFeed accepts it.
type FeedScanner ¶
type FeedScanner struct {
// contains filtered or unexported fields
}
FeedScanner pulls each indexer's RSS forward-feed once per tick, matches items against wanted movies by title+year, and grabs anything that passes the quality filter. Opportunistic — bypasses the missing-search cooldown.
func NewFeedScanner ¶
func NewFeedScanner( store db.Store, indexers IndexerFeeder, grabber Downloader, ) *FeedScanner
type IndexerFeeder ¶
type IndexerFeeder interface {
Feed(ctx context.Context, indexerName string) ([]indexer.SearchResult, error)
}
IndexerFeeder is the subset of indexer.Manager that rss.FeedScanner needs. The enabled-indexer set is read from config; this only fetches a feed by name.
type IndexerSearcher ¶
type IndexerSearcher interface {
SearchMovie(
ctx context.Context,
titles []string,
tmdbID uint32,
) ([]indexer.SearchResult, error)
}
IndexerSearcher is the subset of indexer.Service that rss.MissingSearcher needs.
type MissingSearchRunner ¶
MissingSearchRunner is the consumer-facing surface for triggering one missing-search pass. jobs.RSSSync accepts it so it can be driven by a fake in tests without standing up the full MissingSearcher.
type MissingSearcher ¶
type MissingSearcher struct {
// contains filtered or unexported fields
}
MissingSearcher periodically scans wanted movies, searches indexers, and grabs the best matching release via the download manager.
func NewMissingSearcher ¶
func NewMissingSearcher( store db.Store, indexers IndexerSearcher, downloads Downloader, ) *MissingSearcher
func (*MissingSearcher) Run ¶
func (s *MissingSearcher) Run(ctx context.Context) error
Run performs one sync pass over all eligible wanted movies. Returns a non-nil error only for ctx cancellation; per-movie errors are logged and counted but do not abort the run.
func (*MissingSearcher) SearchOne ¶
SearchOne runs one indexer query for movie m, applies the quality filter, and dispatches a grab on the first acceptable result.
Returns nil on a successful grab, ErrNoEligibleRelease when nothing matches the quality bar, or a wrapped error on indexer / downloader failure. last_search_at is bumped whenever the indexer responds (success or no match) so cooldown counters advance.
type QualityConfig ¶
QualityConfig drives release filtering. It is resolved per item at search time from the movie's or show's quality_profile, so a run picks up profile edits and per-item overrides without a restart.
func (QualityConfig) Accepts ¶
func (q QualityConfig) Accepts(releaseTitle string) bool
Accepts reports whether a release title meets the quality bar. Unparseable titles are rejected (conservative).
type TVIndexerSearcher ¶
type TVIndexerSearcher interface {
SearchSeason(
ctx context.Context,
titles []string,
tvdbID uint32,
season uint16,
) ([]indexer.SearchResult, error)
SearchEpisode(
ctx context.Context,
titles []string,
tvdbID uint32,
season, episode uint16,
) ([]indexer.SearchResult, error)
}
TVIndexerSearcher is the subset of indexer.Manager that rss.EpisodeMissingSearcher needs.