config

package
v0.3.2 Latest Latest
Warning

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

Go to latest
Published: Jul 18, 2026 License: MIT Imports: 15 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 MountProvider = "altmount"

Variables

This section is empty.

Functions

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 {
	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" mapstructure:"nzblnk" json:"nzblnk"`
	Network         NetworkConfig      `yaml:"network" mapstructure:"network" json:"network"`
	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"`
}

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)

LoadConfig loads configuration from file and merges with defaults

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) GetCheckAllSegments

func (c *Config) GetCheckAllSegments() bool

GetCheckAllSegments returns whether to check all segments during health checks.

func (*Config) GetCheckBatchSize added in v0.3.0

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 GetMaxConnectionsForHealthChecks: 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 added in v0.2.0

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 added in v0.3.0

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 added in v0.3.2

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) GetImportDamagePolicyTolerant added in v0.3.0

func (c *Config) GetImportDamagePolicyTolerant() bool

GetImportDamagePolicyTolerant reports whether small confirmed damage on a standalone video file should import as degraded (true, the default) instead of failing the import (false, "strict").

func (*Config) GetIsoAnalyzeTimeout added in v0.3.0

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 added in v0.3.0

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) GetMaxConnectionsForHealthChecks

func (c *Config) GetMaxConnectionsForHealthChecks() int

GetMaxConnectionsForHealthChecks returns max connections for health checks with a default fallback.

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) 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) 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) GetVerifyData

func (c *Config) GetVerifyData() bool

GetVerifyData returns whether to verify data during health checks.

func (*Config) GetWebhookBaseURL added in v0.2.0

func (c *Config) GetWebhookBaseURL() string

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

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) ToNNTPProviders

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

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

func (*Config) TotalProviderConnections added in v0.3.0

func (c *Config) TotalProviderConnections() int

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.

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"`
	MaxConnectionsForHealthChecks       int     `` /* 140-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             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"`
}

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 {
	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"`
	MaxDownloadPrefetch      int            `yaml:"max_download_prefetch" mapstructure:"max_download_prefetch" json:"max_download_prefetch"`
	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"`
	// DamagePolicy governs standalone video files whose fast-fail sweep finds
	// SMALL confirmed damage (within the playback padding caps, see
	// internal/holes): "tolerant" (default) imports them as degraded so
	// streaming zero-fills the gaps; "strict" fails the import so an ARR can
	// grab a different release. Damage beyond the caps, archive-set members
	// and non-video files fail either way.
	DamagePolicy string `yaml:"damage_policy" mapstructure:"damage_policy" json:"damage_policy,omitempty"`
}

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"`
	DeleteSourceNzbOnRemoval *bool                `yaml:"delete_source_nzb_on_removal" mapstructure:"delete_source_nzb_on_removal" json:"delete_source_nzb_on_removal,omitempty"`
	Backup                   MetadataBackupConfig `yaml:"backup" mapstructure:"backup" json:"backup"`
}

MetadataConfig represents metadata filesystem configuration

func (MetadataConfig) ShouldDeleteSourceNzb

func (m MetadataConfig) ShouldDeleteSourceNzb() bool

ShouldDeleteSourceNzb returns whether source NZB files should be deleted on removal.

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 added in v0.3.0

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 added in v0.3.0

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 added in v0.3.0

func (n NetworkConfig) GetHTTPSProxy() string

GetHTTPSProxy returns the configured HTTPS proxy URL.

func (NetworkConfig) GetNoProxy added in v0.3.0

func (n NetworkConfig) GetNoProxy() string

GetNoProxy returns the comma-separated bypass list.

type NzblnkConfig added in v0.3.0

type NzblnkConfig struct {
	// UserAgent is the HTTP User-Agent sent to indexers when resolving nzblnk:// links.
	// Defaults to a browser-like string. Leave empty to use the default.
	UserAgent string `yaml:"user_agent" mapstructure:"user_agent" json:"user_agent,omitempty"`
}

NzblnkConfig configures the NZBLNK resolver (used for nzblnk:// link resolution via public indexers).

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                       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"`
	InflightRequests         int        `yaml:"inflight_requests" mapstructure:"inflight_requests" json:"inflight_requests"`
	StatInflightRequests     int        `yaml:"stat_inflight_requests" mapstructure:"stat_inflight_requests" json:"stat_inflight_requests"`
	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"`
	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"`
	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 name nntppool v4 uses to identify this provider. Format: "host:port" or "host:port+username" when username is set.

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"`
	// 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"`
	// 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"`
}

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"`

	// 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"`
}

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"`
	// 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 int    `yaml:"expiry_hours" mapstructure:"expiry_hours" json:"expiry_hours"`
}

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).

type StreamingConfig

type StreamingConfig struct {
	MaxPrefetch    int                  `yaml:"max_prefetch" mapstructure:"max_prefetch" json:"max_prefetch"`
	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"`
	// 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,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"`
	// Prowlarr configures the Prowlarr indexer used by the Stremio addon to search for NZBs.
	Prowlarr ProwlarrConfig `yaml:"prowlarr" mapstructure:"prowlarr" json:"prowlarr"`
}

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

type StuckCleanupRule added in v0.3.0

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 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