config

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: 22 Imported by: 0

Documentation

Index

Constants

View Source
const (
	// StuckActionRemove removes the item from the queue only (no blocklist, no
	// re-search) — for transient/environmental errors or already-satisfied files.
	StuckActionRemove = "remove"
	// StuckActionBlocklist removes the item and blocklists the release so the same
	// NZB is not grabbed again, but does NOT trigger a new search.
	StuckActionBlocklist = "blocklist"
	// StuckActionBlocklistSearch blocklists the release and triggers the *arr to
	// search for a replacement.
	StuckActionBlocklistSearch = "blocklist_search"
)

Stuck cleanup actions decide what happens to a matched stuck import.

View Source
const DefaultCategoryDir = "complete"
View Source
const DefaultCategoryName = "Default"
View Source
const DefaultMaxDownloadPrefetch = 10

DefaultMaxDownloadPrefetch is the default number of segments to prefetch ahead during archive analysis and expansion. Must match the value in DefaultConfig.

View Source
const DefaultStreamReadTimeout = 120 * time.Second

DefaultStreamReadTimeout bounds a single streaming read when streaming.read_timeout_seconds is unset. A healthy read finishes in seconds; even a pathological one is bounded by the per-segment fetch budget (15s per attempt, 2 attempts). Anything past this is a stall, not slowness.

View Source
const DefaultUserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"

DefaultUserAgent is the fallback for Config.UserAgent. Browser-like because some public indexers (e.g. nzbking.com) reject non-browser agents.

View Source
const MountProvider = "altmount"
View Source
const StreamReadAheadBytesCap int64 = 96 << 20

StreamReadAheadBytesCap bounds one reader's read-ahead window in bytes. The usenet reader enforces it; it lives here so the soft memory limit can budget for the windows that are live while files stream.

Variables

This section is empty.

Functions

func DefaultStreamHeadroom

func DefaultStreamHeadroom(connections int) int

DefaultStreamHeadroom derives the per-stream import reservation from the pool's connection count.

On a saturated link the pool holds slack — connections that are not converting into bytes because the wire, not the pool, is the limit — and handing that slack to playback is close to free. Measured at 100 connections behind a 400 MB/s ceiling: a reservation of 8 cost nothing (import 357 vs 359 MB/s) for stream p50 190ms -> 179ms, and 32 cost 7-13% import throughput during playback only for p50 147ms and p99 245ms -> 170ms.

A quarter of the pool sits between those and, crucially, costs the same share at every pool size. How much slack actually exists depends on the link rate, which cannot be known statically — a small pool on a fast line has little, and will pay something real for this. Set stream_headroom_connections explicitly to override, or 0 to disable.

func SaveToFile

func SaveToFile(config *Config, filename string) error

SaveToFile saves a configuration to a YAML file

Types

type APIConfig

type APIConfig struct {
	Prefix         string   `yaml:"prefix" mapstructure:"prefix" json:"prefix"`
	KeyOverride    string   `yaml:"key_override" mapstructure:"key_override" json:"key_override,omitempty"`
	AllowedOrigins []string `yaml:"allowed_origins" mapstructure:"allowed_origins" json:"allowed_origins,omitempty"`
}

APIConfig represents REST API configuration

type ArrsConfig

type ArrsConfig struct {
	Enabled                        *bool                `yaml:"enabled" mapstructure:"enabled" json:"enabled"`
	MaxWorkers                     int                  `yaml:"max_workers" mapstructure:"max_workers" json:"max_workers,omitempty"`
	WebhookBaseURL                 string               `yaml:"webhook_base_url" mapstructure:"webhook_base_url" json:"webhook_base_url,omitempty"`
	RadarrInstances                []ArrsInstanceConfig `yaml:"radarr_instances" mapstructure:"radarr_instances" json:"radarr_instances"`
	SonarrInstances                []ArrsInstanceConfig `yaml:"sonarr_instances" mapstructure:"sonarr_instances" json:"sonarr_instances"`
	LidarrInstances                []ArrsInstanceConfig `yaml:"lidarr_instances" mapstructure:"lidarr_instances" json:"lidarr_instances"`
	ReadarrInstances               []ArrsInstanceConfig `yaml:"readarr_instances" mapstructure:"readarr_instances" json:"readarr_instances"`
	WhisparrInstances              []ArrsInstanceConfig `yaml:"whisparr_instances" mapstructure:"whisparr_instances" json:"whisparr_instances"`
	SportarrInstances              []ArrsInstanceConfig `yaml:"sportarr_instances" mapstructure:"sportarr_instances" json:"sportarr_instances"`
	QueueCleanupEnabled            *bool                `yaml:"queue_cleanup_enabled" mapstructure:"queue_cleanup_enabled" json:"queue_cleanup_enabled,omitempty"`
	QueueCleanupIntervalSeconds    int                  `` /* 131-byte string literal not displayed */
	QueueCleanupGracePeriodMinutes int                  `` /* 143-byte string literal not displayed */

	// QueueCleanupMaxFailures is the per-target failure circuit breaker. After
	// AltMount has acted on the same target (a Radarr movie or Sonarr/Whisparr
	// episode that keeps failing import) this many times — via queue cleanup,
	// health-repair re-searches or the partial-pack reconcile — it gives up:
	// it blocklists without re-searching and unmonitors the item in the *arr so it
	// stops being automatically re-grabbed. 0 (the default) disables the breaker.
	QueueCleanupMaxFailures int `yaml:"queue_cleanup_max_failures" mapstructure:"queue_cleanup_max_failures" json:"queue_cleanup_max_failures,omitempty"`

	// QueueCleanupRules matches an *arr status message for a stuck/failed import and
	// decides the action (remove / blocklist / blocklist+search). This is the single
	// message-rule list for queue cleanup; ghost/empty-folder detection runs alongside
	// it in the same pass. Only items owned by AltMount's download client are touched
	// (see issue #523).
	QueueCleanupRules []StuckCleanupRule `yaml:"queue_cleanup_rules,omitempty" mapstructure:"queue_cleanup_rules" json:"queue_cleanup_rules,omitempty"`

	// Deprecated: the fields below are read from existing config files for one-time
	// migration into the unified queue-cleanup model (see migrateArrsCleanup) and are
	// cleared afterwards. They are hidden from the API (json:"-") and dropped from
	// saved YAML once empty (yaml omitempty). Do not use in new code.
	QueueCleanupAllowlist          []IgnoredMessage   `yaml:"queue_cleanup_allowlist,omitempty" mapstructure:"queue_cleanup_allowlist" json:"-"`
	StuckCleanupEnabled            *bool              `yaml:"stuck_cleanup_enabled,omitempty" mapstructure:"stuck_cleanup_enabled" json:"-"`
	StuckCleanupGracePeriodMinutes int                `yaml:"stuck_cleanup_grace_period_minutes,omitempty" mapstructure:"stuck_cleanup_grace_period_minutes" json:"-"`
	StuckCleanupRules              []StuckCleanupRule `yaml:"stuck_cleanup_rules,omitempty" mapstructure:"stuck_cleanup_rules" json:"-"`
	// Deprecated: the hardcoded "automatic import is not possible" purge has been
	// folded into the unified QueueCleanupRules (see migrateArrsCleanup). Read for
	// one-time migration only, then cleared. Do not use in new code.
	CleanupAutomaticImportFailure *bool `yaml:"cleanup_automatic_import_failure,omitempty" mapstructure:"cleanup_automatic_import_failure" json:"-"`
}

ArrsConfig represents arrs configuration

type ArrsInstanceConfig

type ArrsInstanceConfig struct {
	APIVersion        string `yaml:"api_version,omitempty" mapstructure:"api_version" json:"api_version,omitempty"`
	Name              string `yaml:"name" mapstructure:"name" json:"name"`
	URL               string `yaml:"url" mapstructure:"url" json:"url"`
	APIKey            string `yaml:"api_key" mapstructure:"api_key" json:"api_key"`
	Category          string `yaml:"category" mapstructure:"category" json:"category,omitempty"`
	Enabled           *bool  `yaml:"enabled" mapstructure:"enabled" json:"enabled,omitempty"`
	SyncIntervalHours *int   `yaml:"sync_interval_hours" mapstructure:"sync_interval_hours" json:"sync_interval_hours,omitempty"`
}

ArrsInstanceConfig represents a single arrs instance configuration

type AuthConfig

type AuthConfig struct {
	LoginRequired *bool `yaml:"login_required" mapstructure:"login_required" json:"login_required"`
}

AuthConfig represents authentication configuration

type ChangeCallback

type ChangeCallback func(oldConfig, newConfig *Config)

ChangeCallback represents a function called when configuration changes

type Config

type Config struct {
	WebDAV       WebDAVConfig       `yaml:"webdav" mapstructure:"webdav" json:"webdav"`
	API          APIConfig          `yaml:"api" mapstructure:"api" json:"api"`
	Auth         AuthConfig         `yaml:"auth" mapstructure:"auth" json:"auth"`
	Database     DatabaseConfig     `yaml:"database" mapstructure:"database" json:"database"`
	Metadata     MetadataConfig     `yaml:"metadata" mapstructure:"metadata" json:"metadata"`
	Streaming    StreamingConfig    `yaml:"streaming" mapstructure:"streaming" json:"streaming"`
	Health       HealthConfig       `yaml:"health" mapstructure:"health" json:"health"`
	RClone       RCloneConfig       `yaml:"rclone" mapstructure:"rclone" json:"rclone"`
	Import       ImportConfig       `yaml:"import" mapstructure:"import" json:"import"`
	Log          LogConfig          `yaml:"log" mapstructure:"log" json:"log"`
	SABnzbd      SABnzbdConfig      `yaml:"sabnzbd" mapstructure:"sabnzbd" json:"sabnzbd"`
	Arrs         ArrsConfig         `yaml:"arrs" mapstructure:"arrs" json:"arrs"`
	Stremio      StremioConfig      `yaml:"stremio" mapstructure:"stremio" json:"stremio"`
	Fuse         FuseConfig         `yaml:"fuse" mapstructure:"fuse" json:"fuse"`
	SegmentCache SegmentCacheConfig `yaml:"segment_cache" mapstructure:"segment_cache" json:"segment_cache"`
	Providers    []ProviderConfig   `yaml:"providers" mapstructure:"providers" json:"providers"`
	Nzblnk       NzblnkConfig       `yaml:"nzblnk,omitempty" mapstructure:"nzblnk" json:"-"`
	Network      NetworkConfig      `yaml:"network" mapstructure:"network" json:"network"`
	// UserAgent is the HTTP User-Agent sent on every outbound HTTP request that
	// identifies AltMount (indexer NZB downloads, metadata lookups, nzblnk://
	// resolution, GitHub release checks). Defaults to a browser-like string
	// because some public indexers reject non-browser agents. Leave empty to
	// use the default.
	UserAgent       string           `yaml:"user_agent" mapstructure:"user_agent" json:"user_agent"`
	Par2Repair      Par2RepairConfig `yaml:"par2_repair" mapstructure:"par2_repair" json:"par2_repair"`
	MountPath       string           `yaml:"mount_path" mapstructure:"mount_path" json:"mount_path"`
	MountType       MountType        `yaml:"mount_type" mapstructure:"mount_type" json:"mount_type"`
	ProfilerEnabled bool             `yaml:"profiler_enabled" mapstructure:"profiler_enabled" json:"profiler_enabled" default:"false"`
	// MemoryLimitMB is the Go soft memory limit. Unset or 0 derives it from
	// the budgets that allocate (see SoftMemoryLimit); a positive value pins
	// it; a negative value leaves the runtime default. GOMEMLIMIT in the
	// environment always takes precedence.
	MemoryLimitMB *int `yaml:"memory_limit_mb" mapstructure:"memory_limit_mb" json:"memory_limit_mb"`
}

Config represents the complete application configuration

func DefaultConfig

func DefaultConfig(configDir ...string) *Config

DefaultConfig returns a config with default values If configDir is provided, it will be used for database and log file paths

func LoadConfig

func LoadConfig(configFile string) (*Config, error)

func (*Config) DeepCopy

func (c *Config) DeepCopy() *Config

DeepCopy returns a deep copy of the configuration using the copier library. This handles all pointer fields, slices, and maps automatically.

func (*Config) GetAcceptableMissingSegmentsPercentage

func (c *Config) GetAcceptableMissingSegmentsPercentage() float64

GetAcceptableMissingSegmentsPercentage returns the missing-segment percentage a health check tolerates before failing a file (and triggering repair) rather than leaving it degraded. Defaults to 2%; set to 0 to disable tolerance entirely (any missing segment fails immediately), or to 100 to disable failing on this basis altogether (always degraded, never repaired for missing segments alone). The value is clamped to [0, 100].

func (*Config) GetCheckAllSegments

func (c *Config) GetCheckAllSegments() bool

GetCheckAllSegments returns whether to check all segments during health checks.

func (*Config) GetCheckBatchSize

func (c *Config) GetCheckBatchSize() int

GetCheckBatchSize returns how many due files each health cycle fetches and sweeps together in one cross-file StatMany call, with a default fallback. Distinct from HealthStatConcurrency: this bounds how many FILES are batched into one sweep, while that bounds how many segment checks run concurrently within a sweep.

func (*Config) GetCheckInterval

func (c *Config) GetCheckInterval() time.Duration

GetCheckInterval returns the health check interval with a default fallback.

func (*Config) GetDownloadClientBaseURL

func (c *Config) GetDownloadClientBaseURL() string

GetDownloadClientBaseURL returns the configured download client base URL or a default one based on the current port.

func (*Config) GetFuseMountPath

func (c *Config) GetFuseMountPath() string

GetFuseMountPath returns the FUSE mount path, falling back to the root mount_path if not set.

func (*Config) GetHealthDeleteOnCorruption

func (c *Config) GetHealthDeleteOnCorruption() bool

GetHealthDeleteOnCorruption reports whether confirmed corruption should delete the file instead of triggering an Arr repair (health.corruption_action == "delete").

func (*Config) GetHealthEnabled

func (c *Config) GetHealthEnabled() bool

GetHealthEnabled returns whether health checking is enabled (defaults to true)

func (*Config) GetHealthExcludedCategories

func (c *Config) GetHealthExcludedCategories() []string

GetHealthExcludedCategories returns the SABnzbd category names whose files must not be registered for health checking by the library-sync pass.

func (*Config) GetHealthReadTimeout

func (c *Config) GetHealthReadTimeout() time.Duration

GetHealthReadTimeout returns the health check read timeout as a duration with a default fallback.

func (*Config) GetHealthVerifyContent

func (c *Config) GetHealthVerifyContent() bool

GetHealthVerifyContent returns whether health checks should probe media files for a valid container signature.

func (*Config) GetHealthVerifyContentTimeout

func (c *Config) GetHealthVerifyContentTimeout() time.Duration

GetHealthVerifyContentTimeout returns the per-file content probe timeout for health check verification, defaulting to 15 seconds.

func (*Config) GetImportVerifyContent

func (c *Config) GetImportVerifyContent() bool

GetImportVerifyContent returns whether imported media files should be probed for a valid container signature before the import is reported successful.

func (*Config) GetImportVerifyContentTimeout

func (c *Config) GetImportVerifyContentTimeout() time.Duration

GetImportVerifyContentTimeout returns the per-file content probe timeout for import verification, defaulting to 15 seconds.

func (*Config) GetIsoAnalyzeTimeout

func (c *Config) GetIsoAnalyzeTimeout() time.Duration

GetIsoAnalyzeTimeout returns the per-ISO analyse deadline with a 120s default fallback. This bounds the entire iso.AnalyzeISO walk so a degraded NNTP provider cannot stall the importer indefinitely.

Sentinel handling:

  • nil (config field unset) → 120s default
  • 0 or negative (explicit "none") → 120s default; users cannot disable the cap — the whole purpose of this knob is to prevent unbounded waits. To approximate "unlimited", set a very large value (e.g. 86400 for a one-day budget).

func (*Config) GetLibrarySyncConcurrency

func (c *Config) GetLibrarySyncConcurrency() int

GetLibrarySyncConcurrency returns the library sync concurrency with a default fallback.

func (*Config) GetLibrarySyncInterval

func (c *Config) GetLibrarySyncInterval() time.Duration

GetLibrarySyncInterval returns the library sync interval with a default fallback.

func (*Config) GetMaxConcurrentImports

func (c *Config) GetMaxConcurrentImports() int

GetMaxConcurrentImports returns the global cap on concurrent NZB imports. 0 means unlimited (the default).

func (*Config) GetMaxConcurrentJobs

func (c *Config) GetMaxConcurrentJobs() int

GetMaxConcurrentJobs returns max concurrent health check jobs with a default fallback.

func (*Config) GetMaxConcurrentSegmentChecks

func (c *Config) GetMaxConcurrentSegmentChecks() int

GetMaxConcurrentSegmentChecks returns the operator's hard cap on in-flight STAT checks during a health sweep, or 0 meaning "let the pool adapt".

func (*Config) GetMaxDownloadPrefetch

func (c *Config) GetMaxDownloadPrefetch() int

GetMaxDownloadPrefetch returns max download prefetch with a default fallback.

func (*Config) GetMaxRepairRetries

func (c *Config) GetMaxRepairRetries() int

GetMaxRepairRetries returns the maximum number of repair notification retries.

func (*Config) GetMaxRetries

func (c *Config) GetMaxRetries() int

GetMaxRetries returns the maximum number of health check retries.

func (*Config) GetMetadataBackupKeep

func (c *Config) GetMetadataBackupKeep() int

GetMetadataBackupKeep returns the number of metadata backups to keep with a default fallback.

func (*Config) GetReadTimeoutSeconds

func (c *Config) GetReadTimeoutSeconds() int

GetReadTimeoutSeconds returns read timeout in seconds with a default fallback.

func (*Config) GetRepairAutoSearchWait

func (c *Config) GetRepairAutoSearchWait() time.Duration

GetRepairAutoSearchWait returns how long a repair may wait for the ARR's own automatic redownload search to finish. Zero means "do not wait".

func (*Config) GetRepairEnabled

func (c *Config) GetRepairEnabled() bool

GetRepairEnabled returns whether automatic repair is enabled (defaults to true)

func (*Config) GetRepairExponentialBackoff

func (c *Config) GetRepairExponentialBackoff() bool

GetRepairExponentialBackoff returns whether exponential backoff is enabled for repairs

func (*Config) GetRepairFileDeleteConfirm

func (c *Config) GetRepairFileDeleteConfirm() time.Duration

GetRepairFileDeleteConfirm returns how long a repair may wait for the ARR to report a deleted file record as unlinked. Zero means "do not wait".

func (*Config) GetRepairInterval

func (c *Config) GetRepairInterval() time.Duration

GetRepairInterval returns the repair check interval

func (*Config) GetRepairMaxCoolDown

func (c *Config) GetRepairMaxCoolDown() time.Duration

GetRepairMaxCoolDown returns the maximum cooldown for repairs

func (*Config) GetSegmentSamplePercentage

func (c *Config) GetSegmentSamplePercentage() int

GetSegmentSamplePercentage returns segment sample percentage with a default fallback. Returns a value between 1 and 100.

func (*Config) GetStreamHeadroomConnections

func (c *Config) GetStreamHeadroomConnections() int

GetStreamHeadroomConnections returns the per-stream import reservation: an explicit setting when present, otherwise a value derived from the pool size.

func (*Config) GetStreamReadTimeout

func (c *Config) GetStreamReadTimeout() time.Duration

GetStreamReadTimeout returns the per-read timeout for streaming reads. Zero configures the default; a negative value disables the timeout entirely and is returned as 0.

func (*Config) GetUserAgent

func (c *Config) GetUserAgent() string

GetUserAgent returns the configured global User-Agent, falling back to DefaultUserAgent when unset.

func (*Config) GetVerifyData

func (c *Config) GetVerifyData() bool

GetVerifyData returns whether to verify data during health checks.

func (*Config) GetWebhookBaseURL

func (c *Config) GetWebhookBaseURL() string

GetWebhookBaseURL returns the configured webhook base URL or a default one based on the current port.

func (*Config) ProviderFingerprint

func (c *Config) ProviderFingerprint() string

TotalProviderConnections returns the pool's total connection capacity: the sum of MaxConnections across enabled, non-backup providers. When no primary providers are configured it falls back to the enabled backup providers' sum so the capacity is not zero while a usable pool exists. Returns 0 when no providers are configured at all. ProviderFingerprint names the set of enabled providers: SHA-1 over the sorted "host:port" list, first 8 bytes hex. Hole records are trusted only under the fingerprint that recorded them, because "missing" is an answer about particular servers.

func (*Config) ProvidersDiff

func (c *Config) ProvidersDiff(other *Config) []ProviderChange

ProvidersDiff computes the set of provider changes between this config and another. Returns nil if providers are identical (same set and same field values).

func (*Config) ProvidersEqual

func (c *Config) ProvidersEqual(other *Config) bool

ProvidersEqual compares the providers in this config with another config for equality

func (*Config) ProvidersOrderChanged

func (c *Config) ProvidersOrderChanged(other *Config) bool

ProvidersOrderChanged returns true if the provider order differs between this config and another, even if the set of providers is unchanged.

func (*Config) SoftMemoryLimit

func (c *Config) SoftMemoryLimit(gomemlimit string) int64

SoftMemoryLimit is the Go soft memory limit to apply, or 0 to leave the runtime alone. Without a limit the collector lets the heap reach twice the live set, so a 256 MB memory tier costs 600+ MB of RSS. The automatic value adds every budget that holds live heap (memory tier, PAR2 solver per concurrent job, read-ahead windows, connection buffers) plus a base, so the limit stays above the live set and the collector never has to run back to back. A soft limit is only useful while the memory tier is on: with it off the heap is small and bursty.

func (*Config) StatConcurrency

func (c *Config) StatConcurrency() int

StatConcurrency returns how many STATs to keep in flight during an availability sweep. STAT carries no body, so nntppool pipelines it down a connection to Provider.StatInflight depth rather than spending one connection per check (see NNTPConnection.inflightSem) — connection count is the wrong ceiling.

The value is the deepest stat_inflight_requests among enabled providers, not the sum of connections × depth. A single provider's pipeline depth is the conservative read: it is what one connection alone can sustain, so the sweep stays within reach even when the pool is busy serving streams.

func (*Config) ToNNTPProviders

func (c *Config) ToNNTPProviders() []nntppool.Provider

ToNNTPProviders converts ProviderConfig slice to nntppool.Provider slice (enabled only)

func (*Config) TotalProviderConnections

func (c *Config) TotalProviderConnections() int

func (*Config) Validate

func (c *Config) Validate() error

Validate validates the configuration

func (*Config) ValidateDirectories

func (c *Config) ValidateDirectories() error

ValidateDirectories validates that all configured directories are writable This performs actual filesystem checks and may create directories if needed

type ConfigGetter

type ConfigGetter func() *Config

ConfigGetter represents a function that returns the current configuration

type DatabaseConfig

type DatabaseConfig struct {
	// Type selects the database backend: "sqlite" (default) or "postgres".
	Type string `yaml:"type" mapstructure:"type" json:"type"`
	// Path is the SQLite database file path (sqlite only).
	Path string `yaml:"path" mapstructure:"path" json:"path"`
	// DSN is the PostgreSQL connection string (postgres only).
	// Example: "postgres://user:password@localhost:5432/altmount?sslmode=disable"
	DSN string `yaml:"dsn" mapstructure:"dsn" json:"dsn,omitempty"`
}

DatabaseConfig represents database configuration

type FailureMaskingConfig

type FailureMaskingConfig struct {
	Enabled   *bool `yaml:"enabled" mapstructure:"enabled" json:"enabled"`
	Threshold int   `yaml:"threshold" mapstructure:"threshold" json:"threshold"`
}

FailureMaskingConfig represents failure masking configuration

type FuseConfig

type FuseConfig struct {
	MountPath           string `yaml:"mount_path" mapstructure:"mount_path" json:"mount_path"`
	Enabled             *bool  `yaml:"enabled" mapstructure:"enabled" json:"enabled"`
	AllowOther          bool   `yaml:"allow_other" mapstructure:"allow_other" json:"allow_other"`
	Debug               bool   `yaml:"debug" mapstructure:"debug" json:"debug"`
	AttrTimeoutSeconds  int    `yaml:"attr_timeout_seconds" mapstructure:"attr_timeout_seconds" json:"attr_timeout_seconds"`
	EntryTimeoutSeconds int    `yaml:"entry_timeout_seconds" mapstructure:"entry_timeout_seconds" json:"entry_timeout_seconds"`
	MaxCacheSizeMB      int    `yaml:"max_cache_size_mb" mapstructure:"max_cache_size_mb" json:"max_cache_size_mb"`
	MaxReadAheadMB      int    `yaml:"max_read_ahead_mb" mapstructure:"max_read_ahead_mb" json:"max_read_ahead_mb"`
	// AsyncBufferSizeMB is the per-open-file read-ahead buffer size (MB). A
	// background goroutine fills it ahead of the player so reads are served
	// from memory instead of blocking on the network, mirroring the buffering
	// rclone's VFS provides over WebDAV. 0 disables read-ahead (every read is a
	// direct passthrough — the previous behavior).
	AsyncBufferSizeMB int `yaml:"async_buffer_size_mb" mapstructure:"async_buffer_size_mb" json:"async_buffer_size_mb"`
	// AsyncBufferMaxTotalMB caps total read-ahead memory across all open files
	// (MB). Buffers reserve their size only while actively streaming; over the
	// cap, additional streams run unbuffered. 0 = unlimited.
	AsyncBufferMaxTotalMB int    `yaml:"async_buffer_max_total_mb" mapstructure:"async_buffer_max_total_mb" json:"async_buffer_max_total_mb"`
	Backend               string `yaml:"backend" mapstructure:"backend" json:"backend"` // "hanwen" or "cgo" (empty = platform default)
	// NoModTime reports epoch for all timestamps (mtime, ctime, atime); prevents
	// media servers re-scanning on unstable VFS mtimes. Note: tools like find -atime
	// will not see meaningful access times on this mount.
	NoModTime bool `yaml:"no_mod_time" mapstructure:"no_mod_time" json:"no_mod_time"`
}

FuseConfig represents FUSE mount configuration

type HealthConfig

type HealthConfig struct {
	Enabled                 *bool   `yaml:"enabled" mapstructure:"enabled" json:"enabled,omitempty"`
	LibraryDir              *string `yaml:"library_dir" mapstructure:"library_dir" json:"library_dir,omitempty"`
	CleanupOrphanedMetadata *bool   `yaml:"cleanup_orphaned_metadata" mapstructure:"cleanup_orphaned_metadata" json:"cleanup_orphaned_metadata,omitempty"`
	CheckIntervalSeconds    int     `yaml:"check_interval_seconds" mapstructure:"check_interval_seconds" json:"check_interval_seconds,omitempty"`
	// MaxConcurrentSegmentChecks bounds how many STAT checks a health sweep keeps
	// in flight. STAT is bodyless and pipelines many per connection, so connection
	// count is the wrong unit — the import path already sizes its sweep by STAT
	// pipeline depth (see importer/processor.go).
	//
	// nil or 0 means "adapt": the pool narrows the sweep to one connection's depth
	// while a stream is playing and widens it to the pool's aggregate STAT capacity
	// when idle, which measured 24x the sweep throughput on an idle pool.
	MaxConcurrentSegmentChecks *int `` /* 128-byte string literal not displayed */

	// Deprecated: superseded by MaxConcurrentSegmentChecks, which is named for
	// what it actually bounds. Read for one-time migration only (see
	// migrateHealthSweepConcurrency), then cleared. Do not use in new code.
	MaxConnectionsForHealthChecks int `` /* 150-byte string literal not displayed */
	CheckBatchSize                int `yaml:"check_batch_size" mapstructure:"check_batch_size" json:"check_batch_size,omitempty"`
	MaxConcurrentJobs             int `yaml:"max_concurrent_jobs" mapstructure:"max_concurrent_jobs" json:"max_concurrent_jobs,omitempty"`
	// SegmentSamplePercentage is the fraction (1-100) of segments randomly sampled
	// during health-check sweeps (post-import validation only). Distinct from
	// Import.SegmentSamplePercentage, which samples during archive extraction.
	// Higher sampling catches more corruption but adds overhead. Default 5%.
	SegmentSamplePercentage             int     `yaml:"segment_sample_percentage" mapstructure:"segment_sample_percentage" json:"segment_sample_percentage,omitempty"`
	MaxRetries                          int     `yaml:"max_retries" mapstructure:"max_retries" json:"max_retries"`
	LibrarySyncIntervalMinutes          int     `` /* 128-byte string literal not displayed */
	LibrarySyncConcurrency              int     `yaml:"library_sync_concurrency" mapstructure:"library_sync_concurrency" json:"library_sync_concurrency,omitempty"`
	ResolveRepairOnImport               *bool   `yaml:"resolve_repair_on_import" mapstructure:"resolve_repair_on_import" json:"resolve_repair_on_import,omitempty"`
	VerifyData                          *bool   `yaml:"verify_data" mapstructure:"verify_data" json:"verify_data,omitempty"`
	CheckAllSegments                    *bool   `yaml:"check_all_segments" mapstructure:"check_all_segments" json:"check_all_segments,omitempty"`
	ReadTimeoutSeconds                  int     `yaml:"read_timeout_seconds" mapstructure:"read_timeout_seconds" json:"read_timeout_seconds,omitempty"`
	AcceptableMissingSegmentsPercentage float64 `` /* 145-byte string literal not displayed */
	// ExcludedCategories lists SABnzbd category names whose files must never be
	// registered for health checking by the library-sync discovery pass. Matching
	// is by the category's configured directory under CompleteDir and is
	// case-insensitive. Empty means no categories are excluded.
	ExcludedCategories []string     `yaml:"excluded_categories" mapstructure:"excluded_categories" json:"excluded_categories,omitempty"`
	Repair             RepairConfig `yaml:"repair" mapstructure:"repair" json:"repair"`
	// CorruptionAction controls what happens when the health checker or a streaming read
	// confirms real (non-degraded) corruption: "repair" (default) triggers an Arr rescan;
	// "delete" removes the file's metadata/NZB/health record and cleans up now-empty
	// parent directories instead. Degraded files are never affected either way.
	CorruptionAction string `yaml:"corruption_action" mapstructure:"corruption_action" json:"corruption_action,omitempty"`
	// VerifyContent, when true, probes each eligible video/audio file's
	// first bytes through the serving stack during a health check and
	// marks the file corrupted if no recognized media container signature
	// is found. Distinct from the unrelated, unused VerifyData field above.
	VerifyContent               *bool `yaml:"verify_content" mapstructure:"verify_content" json:"verify_content,omitempty"`
	VerifyContentTimeoutSeconds *int  `` /* 131-byte string literal not displayed */
	// CorruptedRetentionDays bounds how long the corrupted_metadata safety copies
	// created by MoveToCorrupted are kept before the health cycle prunes them.
	// nil or 0 means keep forever, which is what every install did before this
	// setting existed.
	CorruptedRetentionDays *int `yaml:"corrupted_retention_days" mapstructure:"corrupted_retention_days" json:"corrupted_retention_days,omitempty"`
}

HealthConfig represents health checker configuration

type IgnoredMessage

type IgnoredMessage struct {
	Message string `yaml:"message" mapstructure:"message" json:"message"`
	Enabled bool   `yaml:"enabled" mapstructure:"enabled" json:"enabled"`
}

IgnoredMessage represents an error message to ignore during queue cleanup

type ImportConfig

type ImportConfig struct {
	// RSSFeedURL is an optional indexer cart feed; empty disables polling.
	RSSFeedURL string `yaml:"rss_feed_url" mapstructure:"rss_feed_url" json:"rss_feed_url"`
	// RSSPollIntervalSeconds defaults to 300 when omitted or zero.
	RSSPollIntervalSeconds         int      `yaml:"rss_poll_interval_seconds" mapstructure:"rss_poll_interval_seconds" json:"rss_poll_interval_seconds"`
	MaxProcessorWorkers            int      `yaml:"max_processor_workers" mapstructure:"max_processor_workers" json:"max_processor_workers"`
	QueueProcessingIntervalSeconds int      `` /* 130-byte string literal not displayed */
	AllowedFileExtensions          []string `yaml:"allowed_file_extensions" mapstructure:"allowed_file_extensions" json:"allowed_file_extensions"`
	// MaxConcurrentImports caps the number of NZB imports that may run
	// end-to-end at the same time. 0 = unlimited. NNTP connection use is
	// balanced automatically: imports share the pool's full capacity and
	// yield to streams (priority lane + adaptive connection budget).
	MaxConcurrentImports int `yaml:"max_concurrent_imports" mapstructure:"max_concurrent_imports" json:"max_concurrent_imports"`
	// StreamHeadroomConnections is how many connections are held back from
	// import per active stream. On a saturated link those connections are slack
	// — they are not converting into bytes — so handing them to playback costs
	// little and measurably shortens stream latency. Past that point the pool
	// can no longer fill the link and import throughput really does fall.
	//
	// Measured at 100 connections behind a 400 MB/s link: 8 is free (import
	// 358 vs 359 MB/s) and takes stream p50 190ms -> 179ms; 32 costs ~13% import
	// and takes p50 to 146ms and p99 245ms -> 167ms. The right value depends on
	// the link rate and pool size, so it is a knob rather than a constant.
	// 0 disables the reservation entirely.
	// A nil pointer means "unset, use the default"; an explicit 0 disables the
	// reservation. A plain int cannot express that difference, since YAML omits
	// and YAML-zero both decode to 0.
	StreamHeadroomConnections *int `yaml:"stream_headroom_connections" mapstructure:"stream_headroom_connections" json:"stream_headroom_connections,omitempty"`
	MaxDownloadPrefetch       int  `yaml:"max_download_prefetch" mapstructure:"max_download_prefetch" json:"max_download_prefetch"`
	// SegmentSamplePercentage is the fraction (1-100) of segments randomly sampled
	// during import-phase validation (RAR extraction, archive integrity). Distinct from
	// Health.SegmentSamplePercentage, which samples during post-import health checks.
	// Lower defaults faster imports but skips error detection. Default 1%.
	SegmentSamplePercentage  int            `yaml:"segment_sample_percentage" mapstructure:"segment_sample_percentage" json:"segment_sample_percentage"`
	ReadTimeoutSeconds       int            `yaml:"read_timeout_seconds" mapstructure:"read_timeout_seconds" json:"read_timeout_seconds"`
	IsoAnalyzeTimeoutSeconds *int           `yaml:"iso_analyze_timeout_seconds" mapstructure:"iso_analyze_timeout_seconds" json:"iso_analyze_timeout_seconds,omitempty"`
	ImportStrategy           ImportStrategy `yaml:"import_strategy" mapstructure:"import_strategy" json:"import_strategy"`
	ImportDir                *string        `yaml:"import_dir" mapstructure:"import_dir" json:"import_dir,omitempty"`
	WatchDir                 *string        `yaml:"watch_dir" mapstructure:"watch_dir" json:"watch_dir,omitempty"`
	WatchIntervalSeconds     *int           `yaml:"watch_interval_seconds" mapstructure:"watch_interval_seconds" json:"watch_interval_seconds,omitempty"`
	AllowNestedRarExtraction *bool          `yaml:"allow_nested_rar_extraction" mapstructure:"allow_nested_rar_extraction" json:"allow_nested_rar_extraction,omitempty"`
	ExpandBlurayIso          *bool          `yaml:"expand_bluray_iso" mapstructure:"expand_bluray_iso" json:"expand_bluray_iso,omitempty"`
	RenameToNzbName          *bool          `yaml:"rename_to_nzb_name" mapstructure:"rename_to_nzb_name" json:"rename_to_nzb_name,omitempty"`
	FilterSampleFiles        *bool          `yaml:"filter_sample_files" mapstructure:"filter_sample_files" json:"filter_sample_files,omitempty"`
	FailedItemRetentionHours *int           `yaml:"failed_item_retention_hours" mapstructure:"failed_item_retention_hours" json:"failed_item_retention_hours,omitempty"`
	HistoryRetentionDays     *int           `yaml:"history_retention_days" mapstructure:"history_retention_days" json:"history_retention_days,omitempty"`
	// VerifyContent, when true, probes each eligible video/audio file's
	// first bytes through the serving stack after import and fails the
	// import if no recognized media container signature is found.
	VerifyContent               *bool `yaml:"verify_content" mapstructure:"verify_content" json:"verify_content,omitempty"`
	VerifyContentTimeoutSeconds *int  `` /* 131-byte string literal not displayed */
}

ImportConfig represents import processing configuration

type ImportStrategy

type ImportStrategy string

ImportStrategy represents the import strategy type

const (
	ImportStrategyNone    ImportStrategy = "NONE"
	ImportStrategySYMLINK ImportStrategy = "SYMLINK"
	ImportStrategySTRM    ImportStrategy = "STRM"
)

type LogConfig

type LogConfig struct {
	File       string `yaml:"file" mapstructure:"file" json:"file,omitempty"`                      // Log file path (empty = console only)
	Level      string `yaml:"level" mapstructure:"level" json:"level,omitempty"`                   // Log level (debug, info, warn, error)
	MaxSize    int    `yaml:"max_size" mapstructure:"max_size" json:"max_size,omitempty"`          // Max size in MB before rotation
	MaxAge     int    `yaml:"max_age" mapstructure:"max_age" json:"max_age,omitempty"`             // Max age in days to keep files
	MaxBackups int    `yaml:"max_backups" mapstructure:"max_backups" json:"max_backups,omitempty"` // Max number of old files to keep
	Compress   bool   `yaml:"compress" mapstructure:"compress" json:"compress,omitempty"`          // Compress old log files
}

LogConfig represents logging configuration with rotation support

type Manager

type Manager struct {
	// contains filtered or unexported fields
}

Manager manages configuration state and persistence

func NewManager

func NewManager(config *Config, configFile string) *Manager

NewManager creates a new configuration manager

func (*Manager) ClearLibrarySyncFlag

func (m *Manager) ClearLibrarySyncFlag()

ClearLibrarySyncFlag clears the library sync needed flag

func (*Manager) GetConfig

func (m *Manager) GetConfig() *Config

GetConfig returns the current configuration (thread-safe)

func (*Manager) GetConfigGetter

func (m *Manager) GetConfigGetter() ConfigGetter

GetConfigGetter returns a function that provides the current configuration

func (*Manager) GetPreviousMountPath

func (m *Manager) GetPreviousMountPath() string

GetPreviousMountPath returns the previous mount path before the last change

func (*Manager) NeedsLibrarySync

func (m *Manager) NeedsLibrarySync() bool

NeedsLibrarySync returns whether a library sync is needed due to configuration changes

func (*Manager) OnConfigChange

func (m *Manager) OnConfigChange(callback ChangeCallback)

OnConfigChange registers a callback to be called when configuration changes

func (*Manager) ReloadConfig

func (m *Manager) ReloadConfig() error

ReloadConfig reloads configuration from file

func (*Manager) SaveConfig

func (m *Manager) SaveConfig() error

SaveConfig saves the current configuration to file

func (*Manager) UpdateConfig

func (m *Manager) UpdateConfig(config *Config) error

UpdateConfig updates the current configuration (thread-safe)

func (*Manager) ValidateConfig

func (m *Manager) ValidateConfig(config *Config) error

ValidateConfig validates the configuration using existing validation logic

func (*Manager) ValidateConfigUpdate

func (m *Manager) ValidateConfigUpdate(newConfig *Config) error

ValidateConfigUpdate validates configuration updates with additional restrictions

type MetadataBackupConfig

type MetadataBackupConfig struct {
	Enabled     *bool  `yaml:"enabled" mapstructure:"enabled" json:"enabled"`
	Schedule    string `yaml:"schedule" mapstructure:"schedule" json:"schedule"` // cron expression (UTC)
	KeepBackups int    `yaml:"keep_backups" mapstructure:"keep_backups" json:"keep_backups"`
	Path        string `yaml:"path" mapstructure:"path" json:"path"`
}

MetadataBackupConfig represents metadata backup configuration

type MetadataConfig

type MetadataConfig struct {
	RootPath  string                  `yaml:"root_path" mapstructure:"root_path" json:"root_path"`
	Backup    MetadataBackupConfig    `yaml:"backup" mapstructure:"backup" json:"backup"`
	Migration MetadataMigrationConfig `yaml:"migration" mapstructure:"migration" json:"migration"`
}

MetadataConfig represents metadata filesystem configuration

type MetadataMigrationConfig

type MetadataMigrationConfig struct {
	// DefaultGroup is the newsgroup written into synthesized NzbStore entries.
	// Legacy metas do not retain the original groups, and nzb.BuildNZB renders an
	// empty <groups> element without this, which most NZB clients reject.
	DefaultGroup string `yaml:"default_group" mapstructure:"default_group" json:"default_group"`
}

MetadataMigrationConfig configures the legacy-metadata → v3 migration.

type MountType

type MountType string

MountType represents the active mount system

const (
	MountTypeNone           MountType = "none"
	MountTypeRClone         MountType = "rclone"
	MountTypeFuse           MountType = "fuse"
	MountTypeRCloneExternal MountType = "rclone_external"
)

type NetworkConfig

type NetworkConfig struct {
	HTTPProxy  string `yaml:"http_proxy" mapstructure:"http_proxy" json:"http_proxy,omitempty"`
	HTTPSProxy string `yaml:"https_proxy" mapstructure:"https_proxy" json:"https_proxy,omitempty"`
	NoProxy    string `yaml:"no_proxy" mapstructure:"no_proxy" json:"no_proxy,omitempty"`
}

NetworkConfig holds outbound HTTP routing options applied to every external client (indexers, arrs, SABnzbd fallback, NZBLNK resolver). Internal endpoints (RC server, self-loopback) are unaffected.

Semantics mirror Go's standard HTTP_PROXY/HTTPS_PROXY/NO_PROXY env vars. Empty strings disable proxying for that scheme.

func (NetworkConfig) GetHTTPProxy

func (n NetworkConfig) GetHTTPProxy() string

GetHTTPProxy returns the configured HTTP proxy URL. Implements the httpclient.NetworkProxyConfig interface to avoid config↔httpclient import cycles.

func (NetworkConfig) GetHTTPSProxy

func (n NetworkConfig) GetHTTPSProxy() string

GetHTTPSProxy returns the configured HTTPS proxy URL.

func (NetworkConfig) GetNoProxy

func (n NetworkConfig) GetNoProxy() string

GetNoProxy returns the comma-separated bypass list.

type NewsnabIndexerConfig

type NewsnabIndexerConfig struct {
	ID             string `yaml:"id" mapstructure:"id" json:"id"`
	Name           string `yaml:"name" mapstructure:"name" json:"name"`
	URL            string `yaml:"url" mapstructure:"url" json:"url"`
	APIKey         string `yaml:"api_key" mapstructure:"api_key" json:"api_key"`
	Categories     []int  `yaml:"categories" mapstructure:"categories" json:"categories,omitempty"`
	Weight         int    `yaml:"weight" mapstructure:"weight" json:"weight"`
	TimeoutSeconds int    `yaml:"timeout_seconds" mapstructure:"timeout_seconds" json:"timeout_seconds"`
	Enabled        bool   `yaml:"enabled" mapstructure:"enabled" json:"enabled"`
}

NewsnabIndexerConfig holds configuration for a direct Newznab indexer.

type NzblnkConfig

type NzblnkConfig struct {
	UserAgent string `yaml:"user_agent,omitempty" mapstructure:"user_agent" json:"-"`
}

NzblnkConfig is the legacy scoped user-agent config, retained only so existing YAML files can be migrated into the global user_agent field.

type Par2RepairConfig

type Par2RepairConfig struct {
	// RecoveryMargin is the baseline number of spare recovery rows. Nil keeps
	// eight; zero minimizes arithmetic but may require another full sweep.
	RecoveryMargin *int  `yaml:"recovery_margin,omitempty" mapstructure:"recovery_margin" json:"recovery_margin,omitempty"`
	Enabled        *bool `yaml:"enabled" mapstructure:"enabled" json:"enabled,omitempty"`
	// MaxRepairRatio caps how large a fraction of a file's bytes a repair may
	// reconstruct. The release's PAR2 redundancy is always the hard ceiling.
	MaxRepairRatio float64 `yaml:"max_repair_ratio" mapstructure:"max_repair_ratio" json:"max_repair_ratio,omitempty"`
	// MaxMemoryMB bounds one job's in-heap solver memory; jobs needing more
	// still run, backed by memory-mapped scratch files next to the patch store.
	MaxMemoryMB int `yaml:"max_memory_mb" mapstructure:"max_memory_mb" json:"max_memory_mb,omitempty"`
	// MaxConcurrentJobs bounds simultaneously running repair jobs.
	MaxConcurrentJobs int `yaml:"max_concurrent_jobs" mapstructure:"max_concurrent_jobs" json:"max_concurrent_jobs,omitempty"`
	// MaxConnections bounds how many NNTP connections repair jobs use for
	// article fetches (shared across concurrent jobs). Repair streams the
	// whole release once, so this directly sets its download speed on an idle
	// pool. Fetches ride the pool's background lane: while anything streams
	// or imports, the pool holds repair to a quarter of each provider's
	// connections regardless of this value. 0 (default) means 10.
	MaxConnections int `yaml:"max_connections" mapstructure:"max_connections" json:"max_connections,omitempty"`
	// MinReleaseSizeMB / MaxReleaseSizeMB bound the size of releases repair
	// takes on (content bytes, PAR2 files excluded). A repair downloads the
	// whole release once, so these let users skip releases too large to be
	// worth the bandwidth or too small to bother with. 0 (default) means
	// unbounded on that side — all sizes are repaired.
	MinReleaseSizeMB int `yaml:"min_release_size_mb" mapstructure:"min_release_size_mb" json:"min_release_size_mb,omitempty"`
	MaxReleaseSizeMB int `yaml:"max_release_size_mb" mapstructure:"max_release_size_mb" json:"max_release_size_mb,omitempty"`
	// MaxPatchStoreMB bounds the on-disk patch store size; oldest patches are
	// evicted first when the cap is exceeded. 0 (default) means unlimited.
	MaxPatchStoreMB int `yaml:"max_patch_store_mb" mapstructure:"max_patch_store_mb" json:"max_patch_store_mb,omitempty"`
	// PatchDir is where repaired article payloads (and the solver's transient
	// scratch files) are stored. Empty (default) means <metadata_root>/patches.
	// Applied at startup; changing it does not move existing patches.
	PatchDir string `yaml:"patch_dir" mapstructure:"patch_dir" json:"patch_dir,omitempty"`
	// ArrFirst makes PAR2 repair the fallback for corrupted files: the health
	// worker triggers the ARR rescan first exactly as before, and enqueues a
	// PAR2 repair only when nothing is found in the ARRs (no instance
	// configured, none tracks the file) or ARR repair is disabled. On by
	// default; disable to keep PAR2 out of the corrupted-file flow (degraded
	// files, playback holes and repair-on-import still repair via PAR2
	// directly).
	ArrFirst *bool `yaml:"arr_first" mapstructure:"arr_first" json:"arr_first,omitempty"`
	// RepairOnImport queues a repair as soon as an import completes with
	// confirmed missing segments, instead of waiting for the first playback or
	// a health check. Off by default: every repair costs one full release
	// download, so a large damaged backlog would be expensive. Worth enabling
	// when your library outlives article retention — a release's PAR2 volumes
	// are most likely to still be retrievable close to the post date.
	RepairOnImport *bool `yaml:"repair_on_import" mapstructure:"repair_on_import" json:"repair_on_import,omitempty"`
}

Par2RepairConfig configures background PAR2 repair of missing usenet articles. Repaired article payloads are persisted under <metadata_root>/patches and served on the read path's hole branch.

func (Par2RepairConfig) EffectiveArrFirst

func (p Par2RepairConfig) EffectiveArrFirst() bool

EffectiveArrFirst reports whether corrupted files fall back to PAR2 repair after the ARR repair comes up empty. Defaults to true when unset (configs written before the knob existed).

func (Par2RepairConfig) EffectiveMaxConnections

func (p Par2RepairConfig) EffectiveMaxConnections() int

EffectiveMaxConnections resolves the repair fetch connection bound, defaulting to 10 when unset (configs written before the knob existed).

func (Par2RepairConfig) EffectivePatchDir

func (p Par2RepairConfig) EffectivePatchDir(metadataRoot string) string

EffectivePatchDir resolves where repaired article payloads live: the configured PatchDir, or "patches" under the metadata root when unset.

func (Par2RepairConfig) EffectiveRepairOnImport

func (p Par2RepairConfig) EffectiveRepairOnImport() bool

EffectiveRepairOnImport reports whether imports queue PAR2 repairs. Requires the feature itself to be enabled; defaults to false when unset.

type ProviderChange

type ProviderChange struct {
	Type        ProviderChangeType
	ProviderID  string
	OldProvider *ProviderConfig // nil for Added
	NewProvider *ProviderConfig // nil for Removed
}

ProviderChange describes a single provider change between two configurations.

type ProviderChangeType

type ProviderChangeType int

ProviderChangeType describes the kind of provider change detected by ProvidersDiff.

const (
	ProviderAdded ProviderChangeType = iota
	ProviderRemoved
	ProviderModified
)

type ProviderConfig

type ProviderConfig struct {
	// ID is a stable public identifier used in pool names, metrics, and errors.
	// It must never contain credentials or non-graphic characters.
	ID                  string `yaml:"id" mapstructure:"id" json:"id"`
	Name                string `yaml:"name" mapstructure:"name" json:"name,omitempty"`
	Host                string `yaml:"host" mapstructure:"host" json:"host"`
	Port                int    `yaml:"port" mapstructure:"port" json:"port"`
	Username            string `yaml:"username" mapstructure:"username" json:"username"`
	Password            string `yaml:"password" mapstructure:"password" json:"-"`
	MaxConnections      int    `yaml:"max_connections" mapstructure:"max_connections" json:"max_connections"`
	MinConnectionsAlive int    `yaml:"min_connections_alive" mapstructure:"min_connections_alive" json:"min_connections_alive,omitempty"`
	// InflightRequests caps concurrent decoded article bodies per connection (memory
	// ceiling). In practice, the pool-wide ImportBudget caps total in-flight bodies
	// to roughly the connection count, so each connection carries ~1 body. Peak observed
	// depth is 3-4 against this cap of 10. Raising it does not improve import throughput.
	InflightRequests int `yaml:"inflight_requests" mapstructure:"inflight_requests" json:"inflight_requests"`
	// StatInflightRequests caps the per-connection STAT pipeline depth (bodyless
	// existence checks). Its pool-wide aggregate (connections × depth, clamped to 4096)
	// determines how much an idle-pool health sweep can widen: measured 24x sweep
	// throughput improvement. While a stream is active the sweep is capped lower regardless.
	StatInflightRequests int `yaml:"stat_inflight_requests" mapstructure:"stat_inflight_requests" json:"stat_inflight_requests"`
	// StreamInflightRequests caps streaming (priority-lane) bodies in flight
	// per connection, so a playback read never queues behind a connection's
	// worth of read-ahead. 0 defaults to 4; values above inflight_requests
	// are capped to it.
	StreamInflightRequests   int    `yaml:"stream_inflight_requests" mapstructure:"stream_inflight_requests" json:"stream_inflight_requests,omitempty"`
	TLS                      bool   `yaml:"tls" mapstructure:"tls" json:"tls"`
	InsecureTLS              bool   `yaml:"insecure_tls" mapstructure:"insecure_tls" json:"insecure_tls"`
	ProxyURL                 string `yaml:"proxy_url" mapstructure:"proxy_url" json:"proxy_url,omitempty"`
	Enabled                  *bool  `yaml:"enabled" mapstructure:"enabled" json:"enabled,omitempty"`
	IsBackupProvider         *bool  `yaml:"is_backup_provider" mapstructure:"is_backup_provider" json:"is_backup_provider,omitempty"`
	StorageGroup             string `yaml:"storage_group" mapstructure:"storage_group" json:"storage_group,omitempty"`
	SkipPing                 bool   `yaml:"skip_ping" mapstructure:"skip_ping" json:"skip_ping,omitempty"`
	KeepaliveIntervalSeconds int    `yaml:"keepalive_interval_seconds" mapstructure:"keepalive_interval_seconds" json:"keepalive_interval_seconds,omitempty"`
	KeepaliveCommand         string `yaml:"keepalive_command" mapstructure:"keepalive_command" json:"keepalive_command,omitempty"`
	UserAgent                string `yaml:"user_agent" mapstructure:"user_agent" json:"user_agent,omitempty"`
	// MaxArticleAgeDays is how far back this provider's retention reaches.
	// Articles older than this are fetched from it only after every provider
	// that does reach back that far has been tried, so a short-retention
	// provider absorbs recent posts and leaves the deep-retention providers'
	// connections and quota for the articles that have nowhere else to go.
	// 0 (the default) declares no limit.
	MaxArticleAgeDays int `yaml:"max_article_age_days" mapstructure:"max_article_age_days" json:"max_article_age_days,omitempty"`
	// StrictMaxArticleAge makes MaxArticleAgeDays binding rather than an
	// ordering preference: the provider is not contacted at all for an
	// article older than its retention. For a metered account whose capacity
	// should not be spent on a request that will almost certainly 430.
	StrictMaxArticleAge   bool       `yaml:"strict_max_article_age" mapstructure:"strict_max_article_age" json:"strict_max_article_age,omitempty"`
	QuotaBytes            int64      `yaml:"quota_bytes" mapstructure:"quota_bytes" json:"quota_bytes,omitempty"`
	QuotaPeriodHours      int        `yaml:"quota_period_hours" mapstructure:"quota_period_hours" json:"quota_period_hours,omitempty"`
	LastRTTMs             int64      `yaml:"last_rtt_ms" mapstructure:"last_rtt_ms" json:"last_rtt_ms,omitempty"`
	LastSpeedTestMbps     float64    `yaml:"last_speed_test_mbps" mapstructure:"last_speed_test_mbps" json:"last_speed_test_mbps,omitempty"`
	LastSpeedTestTime     *time.Time `yaml:"last_speed_test_time" mapstructure:"last_speed_test_time" json:"last_speed_test_time,omitempty"`
	AccountExpirationDate string     `yaml:"account_expiration_date" mapstructure:"account_expiration_date" json:"account_expiration_date,omitempty"`
}

ProviderConfig represents a single NNTP provider configuration

func (*ProviderConfig) NNTPPoolName

func (p *ProviderConfig) NNTPPoolName() string

NNTPPoolName returns the stable ID nntppool uses to identify this provider.

func (*ProviderConfig) ToNNTPProvider

func (p *ProviderConfig) ToNNTPProvider() nntppool.Provider

ToNNTPProvider converts a single ProviderConfig to an nntppool.Provider. Does not check the Enabled flag — caller is responsible for that.

type ProwlarrConfig

type ProwlarrConfig struct {
	// Enabled controls whether Prowlarr search is active for the Stremio addon.
	Enabled *bool `yaml:"enabled" mapstructure:"enabled" json:"enabled"`
	// Host is the Prowlarr base URL (e.g. "http://localhost:9696").
	Host string `yaml:"host" mapstructure:"host" json:"host,omitempty"`
	// APIKey is the Prowlarr API key.
	APIKey string `yaml:"api_key" mapstructure:"api_key" json:"api_key,omitempty"`
	// Categories filters search results by Newznab category IDs.
	// Defaults to 5000 (Movies), 5010 (Movies/Foreign), 5030 (TV), 5040 (TV/HD).
	Categories []int `yaml:"categories" mapstructure:"categories" json:"categories,omitempty"`
	// Indexers optionally restricts searches to specific Prowlarr indexer IDs.
	// Empty = search across all configured indexers.
	Indexers []int `yaml:"indexers" mapstructure:"indexers" json:"indexers,omitempty"`
	// PreferredIndexers lists Prowlarr indexer IDs to prioritize and rank above others.
	PreferredIndexers []int `yaml:"preferred_indexers" mapstructure:"preferred_indexers" json:"preferred_indexers,omitempty"`
	// PreferredIndexerNames lists Prowlarr indexer names/keywords to prioritize and rank above others.
	PreferredIndexerNames []string `yaml:"preferred_indexer_names" mapstructure:"preferred_indexer_names" json:"preferred_indexer_names,omitempty"`
	// Languages is an optional list of keywords; releases must contain at least one to pass.
	// Empty = no filtering. Examples: ["Esp", "🇪🇸", "Spanish", "DUAL"]
	Languages []string `yaml:"languages" mapstructure:"languages" json:"languages,omitempty"`
	// PreferredLanguages lists language keywords to prioritize and rank above others.
	PreferredLanguages []string `yaml:"preferred_languages" mapstructure:"preferred_languages" json:"preferred_languages,omitempty"`
	// Qualities is an optional list of keywords; releases must contain at least one to pass.
	// Empty = no filtering. Examples: ["1080p", "HD", "4K", "3D"]
	Qualities []string `yaml:"qualities" mapstructure:"qualities" json:"qualities,omitempty"`
	// ExcludeKeywords is an optional list of keywords/patterns; releases containing any are dropped.
	// Examples: ["DV", "DoVi", "CAM", "TS", "TeleSync"]
	ExcludeKeywords []string `yaml:"exclude_keywords" mapstructure:"exclude_keywords" json:"exclude_keywords,omitempty"`
	// CustomScores maps keyword/regex patterns to numeric scores (TRaSH guide style).
	// Positive scores promote releases; negative scores demote them.
	// Examples: {"2160p": 500, "REMUX": 300, "DV": -1000}
	CustomScores map[string]int `yaml:"custom_scores" mapstructure:"custom_scores" json:"custom_scores,omitempty"`
}

ProwlarrConfig configures the Prowlarr indexer integration for Stremio addon searches.

type RCloneConfig

type RCloneConfig struct {
	// RClone Path
	Path string `yaml:"path" mapstructure:"path" json:"path"`
	// Encryption
	Password string `yaml:"password" mapstructure:"password" json:"-"`
	Salt     string `yaml:"salt" mapstructure:"salt" json:"-"`

	// RC (Remote Control) Configuration
	RCEnabled *bool             `yaml:"rc_enabled" mapstructure:"rc_enabled" json:"rc_enabled"`
	RCUrl     string            `yaml:"rc_url" mapstructure:"rc_url" json:"rc_url"`
	RCPort    int               `yaml:"rc_port" mapstructure:"rc_port" json:"rc_port"`
	RCUser    string            `yaml:"rc_user" mapstructure:"rc_user" json:"rc_user"`
	RCPass    string            `yaml:"rc_pass" mapstructure:"rc_pass" json:"rc_pass,omitempty"`
	RCOptions map[string]string `yaml:"rc_options" mapstructure:"rc_options" json:"rc_options"`

	// Mount Configuration
	MountEnabled *bool             `yaml:"mount_enabled" mapstructure:"mount_enabled" json:"mount_enabled"`
	VFSName      string            `yaml:"vfs_name" mapstructure:"vfs_name" json:"vfs_name"`
	MountOptions map[string]string `yaml:"mount_options" mapstructure:"mount_options" json:"mount_options"`
	LogLevel     string            `yaml:"log_level" mapstructure:"log_level" json:"log_level"`
	UID          int               `yaml:"uid" mapstructure:"uid" json:"uid"`
	GID          int               `yaml:"gid" mapstructure:"gid" json:"gid"`
	Umask        string            `yaml:"umask" mapstructure:"umask" json:"umask"`
	BufferSize   string            `yaml:"buffer_size" mapstructure:"buffer_size" json:"buffer_size"`
	AttrTimeout  string            `yaml:"attr_timeout" mapstructure:"attr_timeout" json:"attr_timeout"`
	Transfers    int               `yaml:"transfers" mapstructure:"transfers" json:"transfers"`

	// VFS Cache Settings
	CacheDir              string `yaml:"cache_dir" mapstructure:"cache_dir" json:"cache_dir"`
	VFSCacheMode          string `yaml:"vfs_cache_mode" mapstructure:"vfs_cache_mode" json:"vfs_cache_mode"`
	VFSCachePollInterval  string `yaml:"vfs_cache_poll_interval" mapstructure:"vfs_cache_poll_interval" json:"vfs_cache_poll_interval"`
	VFSReadChunkSize      string `yaml:"vfs_read_chunk_size" mapstructure:"vfs_read_chunk_size" json:"vfs_read_chunk_size"`
	VFSReadChunkSizeLimit string `yaml:"vfs_read_chunk_size_limit" mapstructure:"vfs_read_chunk_size_limit" json:"vfs_read_chunk_size_limit"`
	VFSCacheMaxSize       string `yaml:"vfs_cache_max_size" mapstructure:"vfs_cache_max_size" json:"vfs_cache_max_size"`
	VFSCacheMaxAge        string `yaml:"vfs_cache_max_age" mapstructure:"vfs_cache_max_age" json:"vfs_cache_max_age"`
	VFSReadAhead          string `yaml:"vfs_read_ahead" mapstructure:"vfs_read_ahead" json:"vfs_read_ahead"`
	DirCacheTime          string `yaml:"dir_cache_time" mapstructure:"dir_cache_time" json:"dir_cache_time"`
	VFSCacheMinFreeSpace  string `yaml:"vfs_cache_min_free_space" mapstructure:"vfs_cache_min_free_space" json:"vfs_cache_min_free_space"`
	VFSDiskSpaceTotal     string `yaml:"vfs_disk_space_total" mapstructure:"vfs_disk_space_total" json:"vfs_disk_space_total"`
	VFSReadChunkStreams   int    `yaml:"vfs_read_chunk_streams" mapstructure:"vfs_read_chunk_streams" json:"vfs_read_chunk_streams"`

	// Mount-Specific Settings
	AllowOther    bool   `yaml:"allow_other" mapstructure:"allow_other" json:"allow_other"`
	AllowNonEmpty bool   `yaml:"allow_non_empty" mapstructure:"allow_non_empty" json:"allow_non_empty"`
	ReadOnly      bool   `yaml:"read_only" mapstructure:"read_only" json:"read_only"`
	Timeout       string `yaml:"timeout" mapstructure:"timeout" json:"timeout"`
	Syslog        bool   `yaml:"syslog" mapstructure:"syslog" json:"syslog"`

	// RcdRestartAfter is how long the rcd subprocess must stay unresponsive to
	// liveness probes before it is killed and restarted. Empty means the built-in
	// default. Restarting is disruptive, because re-establishing the mount
	// unmounts it out from under every process reading it, so an install whose
	// rcd goes briefly slow under load can raise this to ride the stall out.
	RcdRestartAfter string `yaml:"rcd_restart_after" mapstructure:"rcd_restart_after" json:"rcd_restart_after"`

	// Advanced Settings
	NoModTime          bool `yaml:"no_mod_time" mapstructure:"no_mod_time" json:"no_mod_time"`
	NoChecksum         bool `yaml:"no_checksum" mapstructure:"no_checksum" json:"no_checksum"`
	AsyncRead          bool `yaml:"async_read" mapstructure:"async_read" json:"async_read"`
	VFSFastFingerprint bool `yaml:"vfs_fast_fingerprint" mapstructure:"vfs_fast_fingerprint" json:"vfs_fast_fingerprint"`
	UseMmap            bool `yaml:"use_mmap" mapstructure:"use_mmap" json:"use_mmap"`
	Links              bool `yaml:"links" mapstructure:"links" json:"links"`
}

RCloneConfig represents rclone configuration

type RepairConfig

type RepairConfig struct {
	Enabled          *bool `yaml:"enabled" mapstructure:"enabled" json:"enabled,omitempty"`
	IntervalMinutes  int   `yaml:"interval_minutes" mapstructure:"interval_minutes" json:"interval_minutes,omitempty"`
	MaxCoolDownHours int   `yaml:"max_cooldown_hours" mapstructure:"max_cooldown_hours" json:"max_cooldown_hours,omitempty"`
	MaxRepairRetries int   `yaml:"max_repair_retries" mapstructure:"max_repair_retries" json:"max_repair_retries"`

	ExponentialBackoff *bool `yaml:"exponential_backoff" mapstructure:"exponential_backoff" json:"exponential_backoff,omitempty"`

	// AutoSearchWaitSeconds bounds how long a repair waits for the ARR's own
	// automatic redownload search — queued by the ARR the moment a release is
	// blocklisted — to finish before the file record is deleted and AltMount
	// issues its own targeted search. 0 disables the wait and restores the
	// previous fire-and-forget ordering.
	AutoSearchWaitSeconds int `yaml:"auto_search_wait_seconds" mapstructure:"auto_search_wait_seconds" json:"auto_search_wait_seconds"`
	// FileDeleteConfirmSeconds bounds how long a repair waits for the ARR to
	// report the deleted file record as unlinked before issuing its search.
	FileDeleteConfirmSeconds int `yaml:"file_delete_confirm_seconds" mapstructure:"file_delete_confirm_seconds" json:"file_delete_confirm_seconds"`
}

RepairConfig represents repair behavior configuration

type SABnzbdCategory

type SABnzbdCategory struct {
	Name     string `yaml:"name" mapstructure:"name" json:"name"`
	Order    int    `yaml:"order" mapstructure:"order" json:"order"`
	Priority int    `yaml:"priority" mapstructure:"priority" json:"priority"`
	Dir      string `yaml:"dir" mapstructure:"dir" json:"dir"`
	Type     string `yaml:"type" mapstructure:"type" json:"type"` // "sonarr" or "radarr"
}

SABnzbdCategory represents a SABnzbd category configuration

type SABnzbdConfig

type SABnzbdConfig struct {
	Enabled               *bool             `yaml:"enabled" mapstructure:"enabled" json:"enabled"`
	CompleteDir           string            `yaml:"complete_dir" mapstructure:"complete_dir" json:"complete_dir"`
	DownloadClientBaseURL string            `yaml:"download_client_base_url" mapstructure:"download_client_base_url" json:"download_client_base_url,omitempty"`
	Categories            []SABnzbdCategory `yaml:"categories" mapstructure:"categories" json:"categories"`
	// HistoryRetentionMinutes controls how far back the SABnzbd-emulating history
	// endpoint looks into import_history when *arr clients poll without a specific
	// nzo_id filter. Older entries are still returned when *arr asks for them by
	// nzo_id. Defaults to 10080 (7 days).
	HistoryRetentionMinutes int `yaml:"history_retention_minutes" mapstructure:"history_retention_minutes" json:"history_retention_minutes,omitempty"`
	// Zero uses the default; either negative value disables the delete guard.
	DeleteGuardMaxFolders    int `yaml:"delete_guard_max_folders" mapstructure:"delete_guard_max_folders" json:"delete_guard_max_folders"`
	DeleteGuardWindowMinutes int `yaml:"delete_guard_window_minutes" mapstructure:"delete_guard_window_minutes" json:"delete_guard_window_minutes"`
	// Fallback configuration for sending failed imports to external SABnzbd
	FallbackHost   string `yaml:"fallback_host" mapstructure:"fallback_host" json:"fallback_host"`
	FallbackAPIKey string `yaml:"fallback_api_key" mapstructure:"fallback_api_key" json:"fallback_api_key"` // Masked in API responses
}

SABnzbdConfig represents SABnzbd-compatible API configuration

type SegmentCacheConfig

type SegmentCacheConfig struct {
	Enabled   *bool  `yaml:"enabled" mapstructure:"enabled" json:"enabled"`
	CachePath string `yaml:"cache_path" mapstructure:"cache_path" json:"cache_path"`
	MaxSizeGB int    `yaml:"max_size_gb" mapstructure:"max_size_gb" json:"max_size_gb"`
	// ExpiryHours controls how long cached segments are kept before automatic
	// eviction. Set to 0 to disable expiry (cache forever, bounded only by
	// MaxSizeGB via LRU eviction). Left unset (nil) it defaults to 24 hours.
	ExpiryHours *int `yaml:"expiry_hours" mapstructure:"expiry_hours" json:"expiry_hours"`
	// MemoryMB bounds the in-memory tier of decoded articles that sits in
	// front of the disk cache and is on even when the disk cache is off.
	// Left unset (nil) it defaults to 256; an explicit 0 disables it.
	MemoryMB *int `yaml:"memory_mb" mapstructure:"memory_mb" json:"memory_mb"`
}

SegmentCacheConfig configures the segment-aligned disk cache shared by FUSE and WebDAV. When enabled, this cache replaces the FUSE VFS disk cache and additionally benefits WebDAV. Cache key: Usenet message ID. Cache unit: ~750KB decoded segment (matches one NNTP article).

func (SegmentCacheConfig) MemoryBytes

func (c SegmentCacheConfig) MemoryBytes() int64

MemoryBytes is the memory tier budget in bytes (0 = disabled).

type StreamScoringConfig

type StreamScoringConfig struct {
	Preset                   string                    `yaml:"preset" mapstructure:"preset" json:"preset"`
	CustomFormats            []TrashCustomFormatConfig `yaml:"custom_formats" mapstructure:"custom_formats" json:"custom_formats,omitempty"`
	ExcludeKeywords          []string                  `yaml:"exclude_keywords" mapstructure:"exclude_keywords" json:"exclude_keywords,omitempty"`
	ExcludeRegex             string                    `yaml:"exclude_regex,omitempty" mapstructure:"exclude_regex" json:"exclude_regex,omitempty"`
	PreferredLanguages       []string                  `yaml:"preferred_languages" mapstructure:"preferred_languages" json:"preferred_languages,omitempty"`
	RequirePreferredLanguage bool                      `yaml:"require_preferred_language" mapstructure:"require_preferred_language" json:"require_preferred_language"`
}

StreamScoringConfig holds TRaSH scoring configuration.

type StreamingConfig

type StreamingConfig struct {
	MaxPrefetch int `yaml:"max_prefetch" mapstructure:"max_prefetch" json:"max_prefetch"`
	// ReadTimeoutSeconds bounds a single streaming read (WebDAV Read and FUSE
	// ReadAt alike). Nothing below this layer carries a deadline the caller can
	// observe: a segment fetch that stalls without erroring parks the read
	// indefinitely, and on FUSE that means an uninterruptible D-state for the
	// reading process. On expiry the in-flight reader is interrupted and the
	// read fails, so the caller gets an EIO it can act on. 0 uses the built-in
	// default; a negative value disables the timeout.
	ReadTimeoutSeconds int                  `yaml:"read_timeout_seconds" mapstructure:"read_timeout_seconds" json:"read_timeout_seconds"`
	FailureMasking     FailureMaskingConfig `yaml:"failure_masking" mapstructure:"failure_masking" json:"failure_masking"`
}

StreamingConfig represents streaming and chunking configuration

type StremioConfig

type StremioConfig struct {
	// Enabled controls whether the endpoint is active. Disabled by default.
	// When false, the endpoint returns 404 Not Found.
	Enabled *bool `yaml:"enabled" mapstructure:"enabled" json:"enabled"`
	// AddonName is the display name shown in Stremio's addon catalog.
	AddonName string `yaml:"addon_name" mapstructure:"addon_name" json:"addon_name,omitempty"`
	// AddonDescription is the description shown in Stremio's addon catalog.
	AddonDescription string `yaml:"addon_description" mapstructure:"addon_description" json:"addon_description,omitempty"`
	// DirectStream when true streams NZB media segments directly.
	DirectStream *bool `yaml:"direct_stream" mapstructure:"direct_stream" json:"direct_stream,omitempty"`
	// ShowCachedIndicator when true shows cached badges in stream titles.
	ShowCachedIndicator *bool `yaml:"show_cached_indicator" mapstructure:"show_cached_indicator" json:"show_cached_indicator,omitempty"`
	// FallbackTimeoutMs is the timeout before attempting a fallback release.
	FallbackTimeoutMs int `yaml:"fallback_timeout_ms" mapstructure:"fallback_timeout_ms" json:"fallback_timeout_ms,omitempty"`
	// MaxRetries is the maximum number of retry attempts for stream fetching.
	MaxRetries int `yaml:"max_retries" mapstructure:"max_retries" json:"max_retries,omitempty"`
	// StreamTTLSeconds is the stream cache expiration time in seconds.
	StreamTTLSeconds int `yaml:"stream_ttl_seconds" mapstructure:"stream_ttl_seconds" json:"stream_ttl_seconds,omitempty"`
	// NzbTTLHours controls how long a completed NZB result is cached before
	// the same NZB is re-processed on the next request.
	// Set to 0 to disable expiry (cache forever). Defaults to 24 hours.
	NzbTTLHours int `yaml:"nzb_ttl_hours" mapstructure:"nzb_ttl_hours" json:"nzb_ttl_hours"`
	// FailedReleaseTTLHours controls how long a release that failed to import stays
	// excluded from the Stremio stream list. Mirrors NzbTTLHours semantics: it filters
	// failure records by age rather than deleting them, so it is bounded above by
	// Import.FailedItemRetentionHours. Set to 0 to exclude for as long as the record
	// survives. Defaults to 24 hours.
	FailedReleaseTTLHours int `yaml:"failed_release_ttl_hours" mapstructure:"failed_release_ttl_hours" json:"failed_release_ttl_hours"`
	// MaxFallbackReleases caps how many *extra* releases a single play request may try
	// after the first one fails. Set to 0 to disable fallback. Defaults to 2.
	MaxFallbackReleases int `yaml:"max_fallback_releases" mapstructure:"max_fallback_releases" json:"max_fallback_releases"`
	// IncludeLibraryStreams when true checks and presents matching completed files
	// from your Altmount library as instant 0s stream options in Stremio. Defaults to true.
	IncludeLibraryStreams *bool `yaml:"include_library_streams" mapstructure:"include_library_streams" json:"include_library_streams,omitempty"`
	// SkipSearchWhenCached returns matching cached streams without searching indexers.
	// Defaults to false; a cache miss always falls back to the normal search.
	SkipSearchWhenCached bool `yaml:"skip_search_when_cached" mapstructure:"skip_search_when_cached" json:"skip_search_when_cached"`
	// Display controls how releases are labelled in Stremio's stream list.
	Display StremioDisplayConfig `yaml:"display" mapstructure:"display" json:"display"`
	// FastFailHeaderOnly when true causes Stremio-originated imports to fail fast
	// immediately on the release-level probe when missing articles are detected,
	// skipping the multi-part RAR per-file Stat sweep. Defaults to true.
	FastFailHeaderOnly *bool `yaml:"fast_fail_header_only" mapstructure:"fast_fail_header_only" json:"fast_fail_header_only"`
	// SkipRepair when true fails a Stremio-originated import that would need a
	// PAR2 repair instead of parking it for one, so playback falls back to the
	// next release rather than waiting. Defaults to false.
	SkipRepair *bool `yaml:"skip_repair" mapstructure:"skip_repair" json:"skip_repair,omitempty"`
	// BaseURL is the public base URL used when building Stremio stream links
	// (e.g. "https://altmount.example.com"). Falls back to the auto-detected
	// request origin when not set.
	BaseURL string `yaml:"base_url" mapstructure:"base_url" json:"base_url,omitempty"`
	// Indexers configures Prowlarr and direct Newsnab search providers.
	Indexers StremioIndexersConfig `yaml:"indexers" mapstructure:"indexers" json:"indexers"`
	// Scoring configures TRaSH format scoring and exclusions.
	Scoring StreamScoringConfig `yaml:"scoring" mapstructure:"scoring" json:"scoring"`
	// Prowlarr configures the legacy Prowlarr indexer settings (retained for compatibility).
	Prowlarr ProwlarrConfig `yaml:"prowlarr" mapstructure:"prowlarr" json:"prowlarr"`
}

StremioConfig configures the Stremio NZB stream endpoint (POST /api/nzb/streams).

func (StremioConfig) EffectiveFastFailHeaderOnly

func (s StremioConfig) EffectiveFastFailHeaderOnly() bool

func (StremioConfig) EffectiveIncludeLibraryStreams

func (s StremioConfig) EffectiveIncludeLibraryStreams() bool

EffectiveIncludeLibraryStreams reports whether Stremio stream responses should include matching completed releases from the local library. Defaults to true.

func (StremioConfig) EffectiveMaxFallbackReleases

func (s StremioConfig) EffectiveMaxFallbackReleases() int

EffectiveMaxFallbackReleases returns MaxFallbackReleases clamped to [0, 4].

func (StremioConfig) EffectiveSkipRepair

func (s StremioConfig) EffectiveSkipRepair() bool

EffectiveSkipRepair reports whether Stremio imports skip PAR2 repair.

type StremioDisplayConfig

type StremioDisplayConfig struct {
	// Preset is "default", "full", "minimal" or "custom". Empty means default.
	Preset string `yaml:"preset" mapstructure:"preset" json:"preset,omitempty"`
	// NameTemplate and DescriptionTemplate are used when Preset is "custom".
	NameTemplate        string `yaml:"name_template" mapstructure:"name_template" json:"name_template,omitempty"`
	DescriptionTemplate string `yaml:"description_template" mapstructure:"description_template" json:"description_template,omitempty"`
}

EffectiveFastFailHeaderOnly reports whether Stremio imports should fast-fail immediately on the release probe when missing articles are found. Defaults to true. StremioDisplayConfig controls how releases are labelled in Stremio's stream list: the stream's name (the left-hand label) and its description.

type StremioIndexersConfig

type StremioIndexersConfig 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,omitempty"`
	CustomUserAgent string                 `yaml:"custom_user_agent" mapstructure:"custom_user_agent" json:"custom_user_agent,omitempty"`
	Prowlarr        ProwlarrConfig         `yaml:"prowlarr" mapstructure:"prowlarr" json:"prowlarr"`
	Newsnab         []NewsnabIndexerConfig `yaml:"newsnab" mapstructure:"newsnab" json:"newsnab,omitempty"`
}

StremioIndexersConfig configures search providers for the Stremio addon.

type StuckCleanupRule

type StuckCleanupRule struct {
	Message string `yaml:"message" mapstructure:"message" json:"message"`
	Enabled bool   `yaml:"enabled" mapstructure:"enabled" json:"enabled"`
	Action  string `yaml:"action" mapstructure:"action" json:"action"`
}

StuckCleanupRule matches a stuck-import status message and decides the action (one of StuckActionRemove, StuckActionBlocklist, StuckActionBlocklistSearch).

type TrashCustomFormatConfig

type TrashCustomFormatConfig 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"`
	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"`
}

TrashCustomFormatConfig defines a format scoring rule in configuration.

type WebDAVConfig

type WebDAVConfig struct {
	Port     int    `yaml:"port" mapstructure:"port" json:"port"`
	User     string `yaml:"user" mapstructure:"user" json:"user"`
	Password string `yaml:"password" mapstructure:"password" json:"password"`
	Host     string `yaml:"host" mapstructure:"host" json:"host,omitempty"`
}

WebDAVConfig represents WebDAV server configuration

Jump to

Keyboard shortcuts

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