Documentation
¶
Overview ¶
Package quality implements quality profiles: an ordered ranking of file formats, a cutoff, and the accept/upgrade decision that turns "a release exists" into "this release is worth grabbing".
The semantics mirror the rest of the *arr family. A profile lists the formats it is willing to grab, best first. A release whose format is not in the list is never grabbed automatically. When a wanted item already has a file, a release is grabbed only if it is a strictly better format AND the current file has not yet reached the cutoff — once the cutoff is met, the item is satisfied and upgrades stop, even if an even better format appears.
Everything in this package is pure: no database, no HTTP, no clock. The scheduler and API layers feed it strings and act on the Decision.
Index ¶
- Constants
- Variables
- func FormatFromPath(path string) string
- func FormatFromTitle(title string) string
- func Normalize(format string) string
- func State(p Profile, monitored, downloading, hasFile bool, currentFormat string, ...) string
- func Validate(p Profile) error
- type Candidate
- type CandidateDecision
- type Decision
- type Profile
- func (p Profile) Choose(candidates []Candidate, currentFormat string) (*CandidateDecision, []CandidateDecision)
- func (p Profile) CutoffFormat() string
- func (p Profile) CutoffMet(currentFormat string) bool
- func (p Profile) CutoffRank() int
- func (p Profile) Evaluate(candidateFormat, currentFormat string) Decision
- func (p Profile) Rank(format string) (int, bool)
Constants ¶
const ( StateUnmonitored = "unmonitored" StateDownloading = "downloading" StateMissing = "missing" StateUpgrade = "upgrade" // has a file, cutoff not met, upgrades on StateSatisfied = "satisfied" // has a file that meets the cutoff (or upgrades are off) )
Item states, as shown on the wanted list. They are derived, never stored: the stored facts are "monitored", "which file satisfies it" and "is a grab in flight", and the profile turns those into a state.
Variables ¶
var KnownFormats = map[string][]string{
"ebook": {"epub", "azw3", "azw", "kfx", "mobi", "pdf", "fb2", "djvu", "lit", "lrf", "rtf", "txt", "doc", "docx", "html"},
"audiobook": {"m4b", "m4a", "mp3", "flac", "opus", "ogg", "aac", "wma"},
"manga": {"cbz", "cbr", "epub", "pdf", "zip", "rar"},
}
KnownFormats lists the formats the UI offers per media type. The decision engine itself accepts any format string; this list exists so a profile editor can render checkboxes and so validation can reject typos.
Functions ¶
func FormatFromPath ¶
FormatFromPath derives a format from a file name or path by extension.
func FormatFromTitle ¶
FormatFromTitle finds a standalone format token in a release title, such as "Dune - Frank Herbert [EPUB]". It returns "" when no token is present.
func Normalize ¶
Normalize canonicalises a format string: lower-case, no leading dot, no surrounding whitespace. "EPUB", ".epub" and " epub " all become "epub".
Types ¶
type Candidate ¶
type Candidate struct {
// Index lets the caller map the choice back to its own slice.
Index int
Format string
// Score is the search match confidence (0-100). It is a gate applied by
// the caller, and a late tie-break here; quality rank comes first.
Score float64
Size int64
}
Candidate is one release under consideration by Choose.
type CandidateDecision ¶
CandidateDecision pairs a candidate with its decision, for dry runs and logs.
type Decision ¶
type Decision struct {
// Accept reports whether the candidate should be grabbed.
Accept bool
// Upgrade is set when Accept is true because the candidate would replace
// an existing, lower-ranked file.
Upgrade bool
// Rank is the candidate's position in the profile ranking (0 = best), or
// -1 when the format is not in the profile.
Rank int
// Reason is a short human-readable explanation, suitable for logs and for
// the "last result" line on a wanted item.
Reason string
}
Decision is the outcome of evaluating one candidate release.
type Profile ¶
type Profile struct {
ID int64
Name string
MediaType string
// Ranking lists the grabbable formats, best first. Formats absent from the
// ranking are not grabbable under this profile.
Ranking []string
// Cutoff is the format at which upgrading stops. Empty or unknown means
// the best format in the ranking.
Cutoff string
// UpgradesAllowed enables replacing an existing file with a better format.
UpgradesAllowed bool
// PreferredSizeMin/Max (bytes) are a soft tie-break between releases of
// the same format. Zero means no preference on that bound.
PreferredSizeMin int64
PreferredSizeMax int64
}
Profile is a quality profile as the decision engine sees it.
func DefaultProfiles ¶
func DefaultProfiles() []Profile
DefaultProfiles are the built-in profiles seeded on first start, one per media type. They are editable but not deletable, and are what a wanted item uses when no profile has been chosen for it.
func (Profile) Choose ¶
func (p Profile) Choose(candidates []Candidate, currentFormat string) (*CandidateDecision, []CandidateDecision)
Choose evaluates every candidate against the profile and picks the best acceptable one. Quality rank wins; among equal ranks a size inside the preferred window beats one outside it, then the higher match score, then the earlier candidate. The second return value carries every decision so callers can explain a dry run or log why nothing was chosen.
func (Profile) CutoffFormat ¶
CutoffFormat is the effective cutoff after resolving an empty or unknown value to the best format. It is "" only for an empty ranking.
func (Profile) CutoffMet ¶
CutoffMet reports whether a file of the given format satisfies the profile. A format outside the ranking never meets the cutoff.
func (Profile) CutoffRank ¶
CutoffRank is the rank an existing file must reach for the item to count as satisfied. An empty or unknown cutoff means the best ranked format.