Documentation
¶
Index ¶
- Constants
- func CleanSeriesTitle(title string) string
- func MatchesMovie(releaseTitle, expectedTitle string, expectedYear int) bool
- func MatchesSeries(releaseTitle, expectedTitle string, ...) bool
- type CoordinatorConfig
- type HealthRecords
- type ParsedRelease
- type ScoredRelease
- func EvaluateRelease(title string, cfg *StreamScoringConfig) ScoredRelease
- func EvaluateReleases(releases []SearchResult, scoringCfg *StreamScoringConfig, ...) (active, discarded []ScoredRelease)
- func RankAndFilterReleases(releases []SearchResult, scoringCfg *StreamScoringConfig, ...) []ScoredRelease
- type SearchCoordinator
- type SearchInspectResult
- type SearchParams
- type SearchResult
- type StreamScoringConfig
- type StremioCleanupService
- type TrashCustomFormat
- type UserAgentInfo
- type UserAgentManager
- func (m *UserAgentManager) CheckLocalARRs(ctx context.Context, sonarrURL, sonarrKey, radarrURL, radarrKey string) bool
- func (m *UserAgentManager) FetchLatestFromGitHub(ctx context.Context, userAgent string) error
- func (m *UserAgentManager) GetInfo() UserAgentInfo
- func (m *UserAgentManager) GetUserAgent(mediaType string, customOverride string) string
Constants ¶
const ( DefaultSonarrUserAgent = "Sonarr/4.1.1.824 (alpine 3.23.3)" DefaultRadarrUserAgent = "Radarr/6.5.1.2032 (alpine 3.23.3)" )
const OriginalAudio = "Original Audio"
OriginalAudio is the language label for a release with the film's own audio. A release naming no language counts as one: release names tag dubs, not the original audio.
Variables ¶
This section is empty.
Functions ¶
func CleanSeriesTitle ¶
CleanSeriesTitle normalizes a title matching Sonarr/Prowlarr's CleanSeriesTitle: 1. Removes diacritics/accents 2. Converts to lowercase 3. Strips leading articles ("the", "a", "an") 4. Removes year if present 5. Removes all non-alphanumeric characters
func MatchesMovie ¶
MatchesMovie verifies if a release matches the requested movie title and year.
func MatchesSeries ¶
func MatchesSeries(releaseTitle, expectedTitle string, expectedSeason, expectedEpisode, expectedYear int) bool
MatchesSeries verifies if a release matches the requested TV series title and episode.
Types ¶
type CoordinatorConfig ¶
type CoordinatorConfig struct {
Provider string `yaml:"provider" mapstructure:"provider" json:"provider"` // "prowlarr", "newsnab", "both"
UserAgentMode string `yaml:"user_agent_mode" mapstructure:"user_agent_mode" json:"user_agent_mode"` // "auto", "custom"
CustomUserAgent string `yaml:"custom_user_agent" mapstructure:"custom_user_agent" json:"custom_user_agent"`
ProwlarrHost string `yaml:"prowlarr_host" mapstructure:"prowlarr_host" json:"prowlarr_host"`
ProwlarrKey string `yaml:"prowlarr_key" mapstructure:"prowlarr_key" json:"prowlarr_key"`
ProwlarrCats []int `yaml:"prowlarr_categories" mapstructure:"prowlarr_categories" json:"prowlarr_categories"`
ProwlarrIdxs []int `yaml:"prowlarr_indexers" mapstructure:"prowlarr_indexers" json:"prowlarr_indexers"`
NewsnabIndexers []newsnab.IndexerConfig `yaml:"newsnab_indexers" mapstructure:"newsnab_indexers" json:"newsnab_indexers"`
Scoring StreamScoringConfig `yaml:"scoring" mapstructure:"scoring" json:"scoring"`
// PreferredIndexers are indexer ids or names (legacy Prowlarr settings)
// whose releases rank ahead of every other indexer's.
PreferredIndexers []string `yaml:"preferred_indexers" mapstructure:"preferred_indexers" json:"preferred_indexers,omitempty"`
}
CoordinatorConfig defines the search provider configuration.
type HealthRecords ¶
type HealthRecords interface {
GetFileHealth(ctx context.Context, filePath string) (*database.FileHealth, error)
DeleteHealthRecord(ctx context.Context, filePath string) error
}
HealthRecords is the health store the cleanup consults and tidies (satisfied by *database.HealthRepository). Optional: nil skips the library check and health record removal.
type ParsedRelease ¶
type ParsedRelease struct {
SeriesTitle string
CleanTitle string
Season int
SeasonEnd int
EpisodeStart int
EpisodeEnd int
Year int
IsSeasonPack bool
}
ParsedRelease contains parsed metadata from a scene/P2P release title.
func ParseReleaseTitle ¶
func ParseReleaseTitle(title string) ParsedRelease
ParseReleaseTitle parses a release title into its structured components.
type ScoredRelease ¶
type ScoredRelease struct {
SearchResult
Score int `json:"score"`
MatchedFormats []string `json:"matched_formats"`
MatchedLanguages []string `json:"matched_languages"`
Excluded bool `json:"excluded"`
ExcludeReason string `json:"exclude_reason,omitempty"`
// LanguageBonus is the part of Score earned by a preferred language.
LanguageBonus int `json:"language_bonus,omitempty"`
}
ScoredRelease represents a ranked release with evaluation metadata.
func EvaluateRelease ¶
func EvaluateRelease(title string, cfg *StreamScoringConfig) ScoredRelease
EvaluateRelease evaluates a release title against a scoring configuration.
func EvaluateReleases ¶
func EvaluateReleases(releases []SearchResult, scoringCfg *StreamScoringConfig, indexerWeights map[string]int) (active, discarded []ScoredRelease)
EvaluateReleases evaluates every search result against the scoring config and splits them into active and discarded releases with diagnostic reasons. Indexer priority bonuses are applied to active releases only. Active releases are sorted descending by score (ties broken by newest date); discarded ones descending by publish date.
func RankAndFilterReleases ¶
func RankAndFilterReleases(releases []SearchResult, scoringCfg *StreamScoringConfig, indexerWeights map[string]int) []ScoredRelease
RankAndFilterReleases evaluates a list of search results, applies indexer priority bonuses, drops excluded items, and sorts the remaining releases descending by total score.
type SearchCoordinator ¶
type SearchCoordinator struct {
// contains filtered or unexported fields
}
SearchCoordinator coordinates multi-provider indexer searches and ranking.
func NewSearchCoordinator ¶
func NewSearchCoordinator(cfg CoordinatorConfig, httpClient *http.Client) *SearchCoordinator
NewSearchCoordinator creates a new search coordinator.
func (*SearchCoordinator) Search ¶
func (sc *SearchCoordinator) Search(ctx context.Context, params SearchParams) ([]ScoredRelease, error)
Search executes concurrent queries across all enabled providers, deduplicates and ranks results.
func (*SearchCoordinator) SearchInspect ¶
func (sc *SearchCoordinator) SearchInspect(ctx context.Context, params SearchParams) (*SearchInspectResult, error)
SearchInspect queries all enabled providers, evaluates every release against scoring/exclusion rules, and returns both active and discarded releases with diagnostic reasons.
ID-based searches run concurrently first; the broader free-text title searches are dispatched only when the ID pass came back empty, so a typical request costs one round of indexer queries rather than two.
type SearchInspectResult ¶
type SearchInspectResult struct {
TotalResults int `json:"total_results"`
ActiveResults int `json:"active_results"`
DiscardedResults int `json:"discarded_results"`
Releases []ScoredRelease `json:"releases"`
}
SearchInspectResult contains evaluation diagnostics for all releases found during an indexer query.
type SearchParams ¶
type SearchParams struct {
Type string // "movie" or "series"
IMDBID string // "tt1234567"
Title string // "Arcane"
TitleAliases []string // Known alternative titles from metadata.
Season int // 1
Episode int // 1
TVDBID string // optional
TimeoutMS int // e.g. 3500
CustomUA string // optional
}
SearchParams contains the query parameters for a Stremio stream search.
type SearchResult ¶
type SearchResult struct {
Title string `json:"title"`
DownloadURL string `json:"download_url"`
Size int64 `json:"size"`
PublishDate time.Time `json:"publish_date"`
Indexer string `json:"indexer"`
IndexerID string `json:"indexer_id"`
GUID string `json:"guid"`
Source string `json:"source"`
// ByIDSearch reports whether the indexer matched this release via an
// identifier query (imdbid/tvdbid) rather than a keyword. Such results
// skip the media-title mismatch gate, mirroring Prowlarr/Radarr trust
// in identifier matches.
ByIDSearch bool `json:"by_id_search,omitempty"`
}
SearchResult is the common interface for release results from any indexer.
type StreamScoringConfig ¶
type StreamScoringConfig struct {
Preset string `yaml:"preset" mapstructure:"preset" json:"preset"`
CustomFormats []TrashCustomFormat `yaml:"custom_formats" mapstructure:"custom_formats" json:"custom_formats"`
ExcludeKeywords []string `yaml:"exclude_keywords" mapstructure:"exclude_keywords" json:"exclude_keywords"`
ExcludeRegex string `yaml:"exclude_regex,omitempty" mapstructure:"exclude_regex" json:"exclude_regex,omitempty"`
PreferredLanguages []string `yaml:"preferred_languages" mapstructure:"preferred_languages" json:"preferred_languages"`
RequirePreferredLanguage bool `yaml:"require_preferred_language" mapstructure:"require_preferred_language" json:"require_preferred_language"`
// LanguageBonus is the score added when a release matches the first
// preferred language; each subsequent position gets LanguageBonusStep less.
// Left at 0 the defaults below apply. Custom-format scores are typically in
// the hundreds, so these are deliberately configurable rather than fixed —
// an oversized bonus makes every other scoring rule decorative.
LanguageBonus int `yaml:"language_bonus" mapstructure:"language_bonus" json:"language_bonus,omitempty"`
LanguageBonusStep int `yaml:"language_bonus_step" mapstructure:"language_bonus_step" json:"language_bonus_step,omitempty"`
}
StreamScoringConfig holds the full TRaSH format scoring and filter settings.
type StremioCleanupService ¶
type StremioCleanupService struct {
// contains filtered or unexported fields
}
StremioCleanupService periodically removes expired Stremio-originated queue items along with their associated .meta files, storage directory, health records and persistent NZB files. A download the media library has since adopted (an ARR imported the same file) is kept: only its Stremio queue entry is dropped.
func NewStremioCleanupService ¶
func NewStremioCleanupService( queueRepo *database.Repository, metadataService *metadata.MetadataService, health HealthRecords, configGetter config.ConfigGetter, ) *StremioCleanupService
NewStremioCleanupService creates a new StremioCleanupService.
func (*StremioCleanupService) StartCleanup ¶
func (s *StremioCleanupService) StartCleanup(ctx context.Context)
StartCleanup launches a background goroutine that runs cleanup every hour. The goroutine stops when ctx is cancelled.
type TrashCustomFormat ¶
type TrashCustomFormat struct {
ID string `yaml:"id" mapstructure:"id" json:"id"`
Name string `yaml:"name" mapstructure:"name" json:"name"`
Category string `yaml:"category" mapstructure:"category" json:"category"`
Pattern string `yaml:"pattern" mapstructure:"pattern" json:"pattern"`
PatternType string `yaml:"pattern_type" mapstructure:"pattern_type" json:"pattern_type"` // "regex" or "token"
Score int `yaml:"score" mapstructure:"score" json:"score"`
Enabled bool `yaml:"enabled" mapstructure:"enabled" json:"enabled"`
IsCustom bool `yaml:"is_custom" mapstructure:"is_custom" json:"is_custom"`
Invert bool `yaml:"invert,omitempty" mapstructure:"invert" json:"invert,omitempty"`
}
TrashCustomFormat defines a single scoring format rule.
type UserAgentInfo ¶
type UserAgentInfo struct {
TVUserAgent string `json:"tv_user_agent"`
MovieUserAgent string `json:"movie_user_agent"`
SonarrVersion string `json:"sonarr_version"`
RadarrVersion string `json:"radarr_version"`
LastUpdated time.Time `json:"last_updated"`
Source string `json:"source"` // "local_instance", "github_release", "builtin_default"
}
UserAgentInfo holds the current active user agents and detection metadata.
type UserAgentManager ¶
type UserAgentManager struct {
// contains filtered or unexported fields
}
UserAgentManager manages dynamic detection and caching of ARR User-Agents.
func GetUserAgentManager ¶
func GetUserAgentManager() *UserAgentManager
GetUserAgentManager returns the singleton UserAgentManager instance.
func NewUserAgentManager ¶
func NewUserAgentManager(httpClient *http.Client) *UserAgentManager
NewUserAgentManager creates a new UserAgentManager.
func (*UserAgentManager) CheckLocalARRs ¶
func (m *UserAgentManager) CheckLocalARRs(ctx context.Context, sonarrURL, sonarrKey, radarrURL, radarrKey string) bool
CheckLocalARRs attempts to fetch live status from local Sonarr / Radarr instances.
func (*UserAgentManager) FetchLatestFromGitHub ¶
func (m *UserAgentManager) FetchLatestFromGitHub(ctx context.Context, userAgent string) error
FetchLatestFromGitHub queries GitHub releases for latest Sonarr & Radarr version tags. userAgent is the configured User-Agent to send; empty falls back to a static identifier.
func (*UserAgentManager) GetInfo ¶
func (m *UserAgentManager) GetInfo() UserAgentInfo
GetInfo returns the current active User-Agent information.
func (*UserAgentManager) GetUserAgent ¶
func (m *UserAgentManager) GetUserAgent(mediaType string, customOverride string) string
GetUserAgent returns the appropriate User-Agent based on media type and configuration.