stremio

package
v0.4.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 3, 2026 License: MIT Imports: 26 Imported by: 0

Documentation

Index

Constants

View Source
const (
	DefaultSonarrUserAgent = "Sonarr/4.1.1.824 (alpine 3.23.3)"
	DefaultRadarrUserAgent = "Radarr/6.5.1.2032 (alpine 3.23.3)"
)
View Source
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

func CleanSeriesTitle(title string) string

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

func MatchesMovie(releaseTitle, expectedTitle string, expectedYear int) bool

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.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL