Documentation
¶
Overview ¶
Package resolve is the one home for typed-reference resolution (S7): it maps the wire references — FileRef (one stored subtitle file) and MediaRef (the arr-known video of a media item) — to absolute filesystem paths using server-derived facts only. No handler on the file/preview/sync/download verbs accepts a client-supplied path; every path a handler touches comes out of this package (or, for orphans, out of the filehandlers TTL handle table).
Failure taxonomy (mapped by handlers):
- ErrMediaNotFound / ErrSubtitleNotFound -> 404 with the machine code of the same name: the reference does not resolve to a known row/item.
- ErrAmbiguous -> 500-class internal invariant: a FileRef matching more than one store row means the store's uniqueness assumption broke; resolution never guesses.
- ErrPathInvariant -> 500-class: a server-derived path failed the media-roots containment check that runs as defense-in-depth on every resolved value. Server-derived paths should never fail it, so a hit is logged at ERROR as an invariant breach, never answered as a 4xx.
Index ¶
- Variables
- func WriteError(w http.ResponseWriter, r *http.Request, err error)
- type FileRef
- type FileStore
- type MediaRef
- type PathValidator
- type RadarrMovie
- type Resolver
- func (r *Resolver) SubtitlePath(ctx context.Context, ref *FileRef) (string, error)
- func (r *Resolver) SubtitleRow(ctx context.Context, ref *FileRef) (*api.SubtitleEntry, error)
- func (r *Resolver) VideoPath(ctx context.Context, ref *MediaRef) (string, error)
- func (r *Resolver) VideoPathForFile(ctx context.Context, ref *FileRef) (string, error)
- type SonarrEpisodes
- type State
Constants ¶
This section is empty.
Variables ¶
var ( // ErrMediaNotFound means the MediaRef (or a FileRef's surrounding media) // does not resolve to a known media item with a video file. ErrMediaNotFound = errors.New("media not found") // ErrSubtitleNotFound means the FileRef matches no stored subtitle row. ErrSubtitleNotFound = errors.New("subtitle not found") // ErrAmbiguous means the FileRef matched more than one stored row — an // internal invariant breach, never a guess. ErrAmbiguous = errors.New("ambiguous file reference") // ErrPathInvariant means a server-derived path failed the containment // validation that runs as defense-in-depth. ErrPathInvariant = errors.New("resolved path failed containment validation") )
Sentinel errors; see the package doc for the handler status mapping.
Functions ¶
func WriteError ¶
func WriteError(w http.ResponseWriter, r *http.Request, err error)
WriteError maps a resolution error onto the JSON error envelope: the two not-found sentinels answer 404 with their machine codes; everything else (ambiguity, path invariant, store failure) is a 500-class internal error. One mapping site so every reference-taking handler answers identically.
Types ¶
type FileRef ¶
type FileRef struct {
MediaType api.MediaType `json:"media_type"`
MediaID string `json:"media_id"`
Language string `json:"language"`
Variant string `json:"variant"`
Source string `json:"source"`
Ordinal int `json:"ordinal,omitempty"`
}
FileRef addresses exactly one stored subtitle file: the store row identity (media_type, media_id, language, variant, source) plus the manual-sibling ordinal parsed from the row's filename (api.ManualOrdinal; 0 = the unnumbered auto file). A bare quad is NOT unique — manual ordinals share a quad, and sync offsets are path-keyed in the store, so ambiguous resolution would corrupt offset bookkeeping.
MediaID is the store media identifier (e.g. "tmdb-1271", "tvdb-121361-s01e05"), matching the /api/files wire fields.
func FileRefFromQuery ¶
FileRefFromQuery parses a FileRef from GET query parameters (media_type, media_id, language, variant, source, ordinal). Variant defaults to standard and source to external; ordinal defaults to 0. Shape errors are returned for the handler's 400.
type FileStore ¶
type FileStore interface {
GetSubtitleFiles(ctx context.Context, mediaType api.MediaType, mediaIDPrefix string) ([]api.SubtitleEntry, error)
}
FileStore is the store surface resolution needs: the per-media subtitle rows (key-derived identity incl. path; satisfied by api.Store).
type MediaRef ¶
type MediaRef struct {
MediaType api.MediaType `json:"media_type"`
MediaID int `json:"media_id"`
Season int `json:"season,omitempty"`
Episode int `json:"episode,omitempty"`
}
MediaRef addresses the VIDEO of a media item by arr identity: the arr internal ID (Radarr movie ID, Sonarr series ID) plus season/episode for episodes. Resolution asks the arr for the current file path, so it never returns a stale store path. The json field names match the existing download wire contract (media_id = arr ID).
func MediaRefFromQuery ¶
MediaRefFromQuery parses a MediaRef from GET query parameters (media_type, media_id [arr id], season, episode). Shape errors are returned for the handler's 400.
type PathValidator ¶
PathValidator is the containment check run on every resolved path as defense-in-depth (satisfied by api.ConfigProvider).
type RadarrMovie ¶
RadarrMovie is the Radarr surface MediaRef resolution needs.
type Resolver ¶
Resolver resolves typed references against the store and the arrs.
func (*Resolver) SubtitlePath ¶
SubtitlePath resolves a FileRef to the row's absolute subtitle path.
func (*Resolver) SubtitleRow ¶
SubtitleRow resolves a FileRef to its single store row. It filters the media item's rows by the full reference identity; zero matches answer ErrSubtitleNotFound, more than one ErrAmbiguous (see package doc).
func (*Resolver) VideoPath ¶
VideoPath resolves a MediaRef to the arr-known video file path: Radarr's movie file for movies, the season/episode's episode file for episodes. An unconfigured arr, an unknown item, or an item without a file answers ErrMediaNotFound.
func (*Resolver) VideoPathForFile ¶
VideoPathForFile resolves the video path belonging to a FileRef's media: first the resolved row's own subtitle_state join (VideoPath), then any sibling row of the same media item that carries one. A media item whose rows carry no video path (nothing was ever downloaded for it) answers ErrMediaNotFound.
type SonarrEpisodes ¶
type SonarrEpisodes interface {
GetEpisodes(ctx context.Context, seriesID int) ([]arrapi.Episode, error)
}
SonarrEpisodes is the Sonarr surface MediaRef resolution needs.
type State ¶
type State struct {
Cfg PathValidator
Sonarr SonarrEpisodes
Radarr RadarrMovie
}
State is the per-request snapshot of hot-reloadable dependencies. Arr clients are nil when the corresponding arr is not configured.