Documentation
¶
Overview ¶
Package scanning implements the full-scan orchestration engine.
It iterates all wanted episodes and movies from arr APIs, sorts them alphabetically, searches for missing subtitles, and records results. The scheduling infrastructure (timers, goroutine lifecycle) remains in the parent server package.
Index ¶
- Constants
- func EpisodeSearchRequest(series *arrapi.Series, ep *arrapi.Episode, langs []string) api.SearchRequest
- func ExtractAltTitles(alts []arrapi.AlternateTitle, primary string) []string
- func MovieSearchRequest(m *arrapi.Movie, langs []string) api.SearchRequest
- func RunFullScan(ctx context.Context, deps *Deps, ls *LiveState)
- func ScanItemSeasonEp(item ScanItem) (season, episode int)
- func ScanItemTitle(item ScanItem) string
- func SceneOrPath(sceneName, filePath string) string
- func SkipResumed(item ScanItem, recent map[string]bool, stats *api.ScanStats) bool
- type ActivityTracker
- type AlertRecorder
- type BGTracker
- type Deps
- type EventPublisher
- type Handler
- type HandlerDeps
- type HandlerState
- type LiveState
- type ScanGuard
- type ScanHandlerRadarr
- type ScanHandlerSonarr
- type ScanItem
- type ScanMetrics
- type ScanOutcome
- type ScanRadarrClient
- type ScanSonarrClient
- type ScanStore
Constants ¶
const ( ScanFound = api.ScanFound ScanSkipped = api.ScanSkipped ScanNoResult = api.ScanNoResult ScanBackedOff = api.ScanBackedOff )
Scan outcome constants re-exported from api for local use.
Variables ¶
This section is empty.
Functions ¶
func EpisodeSearchRequest ¶
func EpisodeSearchRequest(series *arrapi.Series, ep *arrapi.Episode, langs []string) api.SearchRequest
EpisodeSearchRequest builds a SearchRequest from arr Series+Episode data. This is the single source of truth for the episode→SearchRequest mapping, used by both scanning and polling.
func ExtractAltTitles ¶
func ExtractAltTitles(alts []arrapi.AlternateTitle, primary string) []string
ExtractAltTitles returns unique alternative titles, excluding the primary.
func MovieSearchRequest ¶
func MovieSearchRequest(m *arrapi.Movie, langs []string) api.SearchRequest
MovieSearchRequest builds a SearchRequest from arr Movie data. This is the single source of truth for the movie→SearchRequest mapping, used by both scanning and polling.
func RunFullScan ¶
RunFullScan iterates all wanted episodes and movies, searching for missing subtitles. Episodes and movies are sorted alphabetically by title.
func ScanItemSeasonEp ¶
ScanItemSeasonEp returns season and episode for sorting.
func ScanItemTitle ¶
ScanItemTitle returns the title used for sort ordering.
func SceneOrPath ¶
SceneOrPath returns sceneName if non-empty, otherwise filePath.
Types ¶
type ActivityTracker ¶
type ActivityTracker interface {
Start(action, detail string, source activity.ActivitySource) string
End(id string)
Fail(id string)
Progress(id string, current, total int, msg string)
SetQueued(id string, queued bool)
IsCancelled(id string) bool
}
ActivityTracker manages scan activity lifecycle.
type AlertRecorder ¶
AlertRecorder records alerts visible in the UI.
type BGTracker ¶
type BGTracker interface {
Add(delta int)
Done()
}
BGTracker allows the scanning handler to register background goroutines with the server's WaitGroup for graceful shutdown.
type Deps ¶
type Deps struct {
DB ScanStore
Metrics ScanMetrics
Events EventPublisher
Activity ActivityTracker
Alerts AlertRecorder
ShowSkipCache *showskip.Cache
// SleepCtx is a context-aware sleep function injected to avoid importing provider/.
SleepCtx func(ctx context.Context, d time.Duration) error
// ClearCaches clears provider download caches after scan completion.
ClearCaches func(providers []api.Provider)
}
Deps holds the narrow dependencies the scan orchestration needs from the server. This avoids importing the full Server struct.
type EventPublisher ¶
type EventPublisher interface {
PublishCoverageUpdate(mediaType api.MediaType, mediaID string)
PublishScanStart(action, detail string, source activity.ActivitySource)
PublishScanDone(action, detail string, source activity.ActivitySource, ok bool)
}
EventPublisher publishes events to SSE clients.
type Handler ¶
type Handler struct {
// contains filtered or unexported fields
}
Handler provides HTTP handlers for the /api/scan/* endpoints.
func NewHandler ¶
func NewHandler(deps HandlerDeps) *Handler
NewHandler creates a scan Handler with the given dependencies.
func (*Handler) HandleScanItem ¶
func (h *Handler) HandleScanItem(w http.ResponseWriter, r *http.Request)
HandleScanItem scans a single episode or movie. POST /api/scan/item with JSON body.
func (*Handler) HandleScanMovie ¶
func (h *Handler) HandleScanMovie(w http.ResponseWriter, r *http.Request)
HandleScanMovie scans all missing subtitles for a specific movie. POST /api/scan/movie/{radarrId}
func (*Handler) HandleScanSeason ¶
func (h *Handler) HandleScanSeason(w http.ResponseWriter, r *http.Request)
HandleScanSeason scans all missing subtitles for a specific season. POST /api/scan/season/{sonarrId}/{seasonNum}
func (*Handler) HandleScanSeries ¶
func (h *Handler) HandleScanSeries(w http.ResponseWriter, r *http.Request)
HandleScanSeries scans all missing subtitles for a specific series. POST /api/scan/series/{sonarrId}
type HandlerDeps ¶
type HandlerDeps struct {
// StateFunc returns the current live state snapshot.
StateFunc func() *HandlerState
// CtxFunc returns the server-level context (outlives individual requests).
CtxFunc func() context.Context
// ScanDeps provides the scanning engine dependencies.
ScanDeps func() *Deps
// ScanLiveStateFunc converts HandlerState to scanning.LiveState.
ScanLiveStateFunc func() *LiveState
// Activity tracks scan activity lifecycle.
Activity ActivityTracker
// ScanGuard serializes manual scan requests.
ScanGuard *ScanGuard
// Alerts records alerts visible in the UI.
Alerts AlertRecorder
// Events publishes SSE events.
Events EventPublisher
// InvalidateStats clears the stats cache after scan completion.
InvalidateStats func()
// BGTracker tracks background goroutine lifecycle for graceful shutdown.
BGTracker BGTracker
}
HandlerDeps holds the dependencies for the scan HTTP handler family.
type HandlerState ¶
type HandlerState struct {
Cfg api.ConfigProvider
Engine api.SearchEngine
Sonarr ScanHandlerSonarr // nil when sonarr not configured
Radarr ScanHandlerRadarr // nil when radarr not configured
}
HandlerState holds the runtime state needed by scan HTTP handlers. Provided by the server on each request via the StateFunc callback.
type LiveState ¶
type LiveState struct {
Cfg api.ConfigProvider
Engine api.SearchEngine
Sonarr ScanSonarrClient
Radarr ScanRadarrClient
ShowCounter api.ShowSubtitleCounter
Providers []api.Provider
}
LiveState holds the runtime state needed for a scan pass.
type ScanGuard ¶
type ScanGuard struct {
// contains filtered or unexported fields
}
ScanGuard serializes manual scan requests. Extracted from activity.Log to separate coordination concerns from data concerns.
type ScanHandlerRadarr ¶ added in v0.1.106
type ScanHandlerRadarr interface {
GetMovieByID(ctx context.Context, id int) (arrapi.Movie, error)
}
ScanHandlerRadarr is the Radarr surface the manual scan HTTP handlers call.
type ScanHandlerSonarr ¶ added in v0.1.106
type ScanHandlerSonarr interface {
GetSeriesByID(ctx context.Context, id int) (arrapi.Series, error)
GetEpisodes(ctx context.Context, seriesID int) ([]arrapi.Episode, error)
}
ScanHandlerSonarr is the Sonarr surface the manual scan HTTP handlers call.
type ScanItem ¶
type ScanItem struct {
Series *arrapi.Series // non-nil for episodes
Ep *arrapi.Episode // non-nil for episodes
Movie *arrapi.Movie // non-nil for movies
}
ScanItem holds either an episode or a movie for alphabetical scanning.
func SortByTitle ¶
SortByTitle merges episodes and movies into a single slice sorted alphabetically by title (case-insensitive).
type ScanMetrics ¶
ScanMetrics records scan-level metrics.
type ScanOutcome ¶
type ScanOutcome = api.ScanOutcome
ScanOutcome is a type alias for api.ScanOutcome.
func ScanEpisode ¶
func ScanEpisode(ctx context.Context, deps *Deps, ls *LiveState, series *arrapi.Series, ep *arrapi.Episode, forceUpgrade ...bool) (outcome ScanOutcome, searchedLangs, foundLangs []string)
ScanEpisode searches for subtitles for a single episode. Returns the scan outcome, the language codes whose group actually ran (searchedLangs — the only langs the season tracker may record), and the language codes that had at least one subtitle downloaded (foundLangs, a subset of searchedLangs).
type ScanRadarrClient ¶ added in v0.1.106
type ScanRadarrClient interface {
GetWantedMovies(ctx context.Context, excludeTagIDs map[int]struct{}, fn func(arrapi.Movie) error) error
ResolveExcludeTagIDs(ctx context.Context, tagNames []string, logMissing bool) map[int]struct{}
RescanMovie(ctx context.Context, movieID int) error
}
ScanRadarrClient is the Radarr surface the full-scan engine needs.
type ScanSonarrClient ¶ added in v0.1.106
type ScanSonarrClient interface {
GetWantedEpisodes(ctx context.Context, excludeTagIDs map[int]struct{}, fn func(arrapi.Series, arrapi.Episode) error) error
ResolveExcludeTagIDs(ctx context.Context, tagNames []string, logMissing bool) map[int]struct{}
RescanSeries(ctx context.Context, seriesID int) error
}
ScanSonarrClient is the Sonarr surface the full-scan engine needs: wanted-episode iteration, exclude-tag resolution, and a post-download rescan.