config

package
v0.80.2 Latest Latest
Warning

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

Go to latest
Published: Jul 4, 2026 License: MIT Imports: 11 Imported by: 0

Documentation

Index

Constants

View Source
const (
	StorageBackendFile = "file"
	StorageBackendMmap = "mmap"
)

StorageBackendFile/Mmap são os valores válidos de StreamConfig.StorageBackend.

Variables

This section is empty.

Functions

func ActiveEnvOverrides

func ActiveEnvOverrides() map[string]string

func CheckWritable

func CheckWritable(path string) error

CheckWritable reports whether path can be opened for writing — used at boot to warn early that Settings/Mounts changes won't persist (typical cause: the host file is owned by root while the container runs as uid 1000).

func DefaultFreeModels

func DefaultFreeModels(provider string) []string

DefaultFreeModels exposes the built-in free-id fallback for a provider (used by the ai package when a provider's config sets no FreeModels override).

func EffectiveRPM

func EffectiveRPM(provider string, configRPM int) int

EffectiveRPM returns the requests/min cap for a provider: the config override (configRPM) when > 0, else the built-in default (0 = unthrottled). Used by the ai client to pace calls.

func IsFreeGoogleModel

func IsFreeGoogleModel(model string, free []string) bool

IsFreeGoogleModel reports whether a Google model id is on the free tier, given the effective free list (exact match on the prefix-normalized id, so a paid look-alike like gemini-3.5-flash is never treated as free). Pure — callers pass the config-or-default list.

Types

type AIChainSlot

type AIChainSlot struct {
	ID       string `yaml:"id"`       // unique label (used by the benchmark + logs)
	Provider string `yaml:"provider"` // key into Providers
	Model    string `yaml:"model"`    // model id sent to /chat/completions
	// Disabled lets the benchmark (Fase 3) park a model without deleting it.
	Disabled bool `yaml:"disabled"`
}

type AIConfig

type AIConfig struct {
	Enabled   bool                  `yaml:"enabled"`
	Providers map[string]AIProvider `yaml:"providers"`
	Chain     []AIChainSlot         `yaml:"chain"`
	// MaxCostPer1M caps which models the benchmark will TEST (and thus pay for),
	// in USD per 1M tokens (blended prompt+completion). 0 (default) = free models
	// only — paid models are never called, so the benchmark spends nothing. Raise
	// it to also test paid models up to that price; the composite score then ranks
	// by cost too (cheaper wins), so it's value-based, not a binary free/paid flag.
	MaxCostPer1M float64 `yaml:"max_cost_per_1m"`
	// ElectricityPricePerKWh and LocalPowerWatts price the ENERGY of LOCAL models —
	// they aren't truly free (the GPU draws power). When the price is > 0 the
	// benchmark estimates a local model's $/1M from its measured latency × tokens ×
	// power × tariff, so a slow/power-hungry local model ranks below a fast
	// cloud-free one. Price 0 (default) keeps local at cost 0. Watts defaults to 250.
	ElectricityPricePerKWh float64 `yaml:"electricity_price_per_kwh"`
	LocalPowerWatts        float64 `yaml:"local_power_watts"`
}

AIConfig declares an OpenAI-compatible LLM fallback chain used to turn a messy torrent name into a clean title before the TMDB lookup. Entirely optional: with no providers/chain (or enabled:false) the resolver falls back to TMDB's own regex title cleaning. Providers are keyed by name; the chain references them by `provider` and is walked in order until one returns a usable title.

type AIProvider

type AIProvider struct {
	BaseURL string `yaml:"base_url"` // OpenAI-compatible base, e.g. https://api.groq.com/openai/v1
	APIKey  string `yaml:"api_key"`  // bearer token; empty for keyless backends (ollama)
	// PreferredModels overrides the built-in pick order for this provider's default chain
	// slot (empty → the defaultProviderModels fallback). It only biases WHICH model this
	// provider offers pre-benchmark; the chain ORDER is always the benchmark's job.
	PreferredModels []string `yaml:"preferred_models,omitempty"`
	// FreeModels overrides the pinned free-tier id list for providers whose free tier
	// can't be discovered (Google — its /models has no pricing). Empty → the default.
	// Update this instead of the code when a provider ships/reprices a free model.
	FreeModels []string `yaml:"free_models,omitempty"`
	// RPM caps requests-per-minute to this provider so a burst benchmark doesn't trip a
	// free-tier rate limit and leave models "incomplete". 0 → the built-in default (see
	// defaultProviderModels; Google's free tier is ~30/min). Set high to disable throttling.
	RPM int `yaml:"rpm,omitempty"`
}

type AuthConfig

type AuthConfig struct {
	Enabled       bool   `yaml:"enabled"`        // false = legacy no-auth mode (everything public)
	JWTSecret     string `yaml:"jwt_secret"`     // HS256 secret; REQUIRED (>=32 bytes) when auth enabled — boot fails otherwise
	AdminUsername string `yaml:"admin_username"` // bootstrap admin login
	AdminPassword string `yaml:"admin_password"` // bootstrap admin password (only used on first run)
	DBPath        string `yaml:"db_path"`        // auth DB (defaults to /data/auth.db)
}

type BandwidthSchedule

type BandwidthSchedule struct {
	TimeRange       string `yaml:"time_range"`        // e.g. "08:00-18:00"
	MaxDownloadRate int64  `yaml:"max_download_rate"` // bytes/sec
	MaxUploadRate   int64  `yaml:"max_upload_rate"`   // bytes/sec
}

type Config

type Config struct {
	Jackett struct {
		URL    string `yaml:"url"`
		APIKey string `yaml:"api_key"`
	} `yaml:"jackett"`
	DownloadClients []DownloadClient `yaml:"download_clients"`
	Port            int              `yaml:"port"`
	// DatabaseURL is the PostgreSQL DSN for the unified data store (the single
	// source of truth for all state). Env: JACKUI_DATABASE_URL (preferred) or
	// DATABASE_URL.
	DatabaseURL    string               `yaml:"database_url"`
	Stream         StreamConfig         `yaml:"stream"`
	Subtitles      SubtitlesConfig      `yaml:"subtitles"`
	Auth           AuthConfig           `yaml:"auth"`
	Notifications  NotificationsConfig  `yaml:"notifications"`
	TMDB           TMDBConfig           `yaml:"tmdb"`
	External       ExternalConfig       `yaml:"external"`
	AI             AIConfig             `yaml:"ai"`
	SMTP           SMTPConfig           `yaml:"smtp"`
	DownloadsQueue DownloadsQueueConfig `yaml:"downloads_queue"`
	// BaseURL is the public URL of the app (e.g. https://jackui.example.com),
	// used to build links in emails (reset/verify/invite). Falls back to the
	// request's Origin when empty.
	BaseURL string `yaml:"base_url"`
}

func Load

func Load(path string) (*Config, error)

func (*Config) Save

func (c *Config) Save(path string) error

type DownloadClient

type DownloadClient struct {
	ID       string `yaml:"id"`
	Name     string `yaml:"name"`
	Type     string `yaml:"type"` // "qbittorrent" or "transmission"
	URL      string `yaml:"url"`
	Username string `yaml:"username"`
	Password string `yaml:"password"`
	Default  bool   `yaml:"default"`
}

type DownloadsQueueConfig

type DownloadsQueueConfig struct {
	MaxActive         int  `yaml:"max_active"`          // GLOBAL ceiling: concurrent downloads across all users (streaming excluded); default 3
	PerUserMaxActive  int  `yaml:"per_user_max_active"` // per-user concurrent cap; 0 = no per-user limit (only the global ceiling applies); default 0
	StallThresholdMin int  `yaml:"stall_threshold_min"` // no-progress+no-seed minutes before a demote; default 30
	MaxStalls         int  `yaml:"max_stalls"`          // stalls before pausing the download; default 3 (0 = cycle forever)
	AgingStepMin      int  `yaml:"aging_step_min"`      // queue aging: minutes waited per +1 bonus; default 60
	AgingCap          int  `yaml:"aging_cap"`           // ceiling on the aging bonus; default 150
	RotationEnabled   bool `yaml:"rotation_enabled"`    // Phase 2: auto source rotation via Jackett; default false
	// AutoPromoteArr: when on, a completed download created via the Transmission
	// RPC (Sonarr/Radarr) is written straight into SharedDir/<category>/ — the
	// same "completed downloads" tree Transmission uses — so the *arr import it as
	// expected. UI downloads are unaffected. Needs Stream.SharedDir set. Default off.
	AutoPromoteArr bool `yaml:"auto_promote_arr"`
}

DownloadsQueueConfig tunes the background-download scheduler: how many run at once, when a no-seed download is bumped to the back of the queue, and the queue's anti-starvation aging. RotationEnabled gates the Phase-2 automatic source rotation (re-search Jackett when a source dries up).

type ExternalConfig

type ExternalConfig struct {
	Mounts []ExternalMount `yaml:"mounts"`
	// MaxUploadMB caps a single local upload (anti disk-fill DoS). 0 = default.
	MaxUploadMB int `yaml:"max_upload_mb"`
	// LocalReadaheadMB is the read-ahead buffer used when serving/transcoding a
	// file from a local mount. On rclone/Drive mounts a larger aligned read-ahead
	// turns many tiny FUSE Range reads into a few big fetches, smoothing playback.
	// 0 → 16 MiB default. Distinct from Stream.ReadaheadMB (torrent-only).
	LocalReadaheadMB int `yaml:"local_readahead_mb"`
	// LocalCacheGB caps the dedicated cache that pre-fetches whole files from
	// slow mounts (rclone/Drive) to local disk for instant, seekable, EIO-proof
	// playback. LRU eviction keeps it under the cap. 0 → 50 GiB default.
	LocalCacheGB int `yaml:"local_cache_gb"`
}

ExternalConfig declares filesystem mounts the user wants browsable from the web UI — typical setups: bind-mount an external HDD or NAS share so the Local Files page lists what's already on disk.

type ExternalMount

type ExternalMount struct {
	Name         string   `yaml:"name" json:"name"`                  // Display name shown in the UI ("HD Externo", "NAS")
	Path         string   `yaml:"path" json:"path"`                  // Absolute path inside the container
	AllowedUsers []string `yaml:"allowed_users" json:"allowedUsers"` // Empty = visible to all; otherwise only these usernames
	UserSubpath  bool     `yaml:"user_subpath" json:"userSubpath"`   // When true, each user sees/writes only their own subdir
}

type NotificationsConfig

type NotificationsConfig struct {
	NtfyBaseURL       string `yaml:"ntfy_base_url"`      // default https://ntfy.sh
	NtfyDefaultTopic  string `yaml:"ntfy_default_topic"` // used when a watchlist has no override
	NtfyToken         string `yaml:"ntfy_token"`         // access token for protected/self-hosted topics (sent as Authorization: Bearer)
	WatchlistInterval int    `yaml:"watchlist_minutes"`  // poll interval in minutes (default 15)
}

type PromoteDir

type PromoteDir struct {
	Name string `yaml:"name"`
	Path string `yaml:"path"`
}

type SMTPConfig

type SMTPConfig struct {
	Host     string `yaml:"host"`
	Port     int    `yaml:"port"`
	Username string `yaml:"username"`
	Password string `yaml:"password"`
	From     string `yaml:"from"` // From: address; defaults to Username when empty
}

SMTPConfig configures outbound email (password reset, email verification, invites). Empty Host disables email — the relevant flows then expose a copyable link to the admin instead of sending mail.

type StreamConfig

type StreamConfig struct {
	DataDir         string `yaml:"data_dir"`         // where torrent pieces are stored
	DownloadDir     string `yaml:"download_dir"`     // where completed downloads are moved (empty = stay in cache)
	SharedDir       string `yaml:"shared_dir"`       // shared library destination for "Promote" (empty = feature disabled)
	IdleMinutes     int    `yaml:"idle_minutes"`     // drop torrent after N min idle (files stay)
	MetadataSeconds int    `yaml:"metadata_seconds"` // metadata fetch timeout
	MaxCacheGB      int    `yaml:"max_cache_gb"`     // total cache size cap; 0 = unlimited
	// MaxConcurrentTransfers caps simultaneous file move/copy operations (post-
	// download move, Local-tab move); the rest queue FIFO. 0 = default (3). Higher
	// helps cloud/rclone destinations; lower (1-2) is better for a single HDD.
	MaxConcurrentTransfers int `yaml:"max_concurrent_transfers"`
	// TransferConcurrencyMode controla como as cópias de promote/move concorrem:
	//   "" / "auto" → detecta o disco DESTINO: serializa em HDD (evita seek
	//                 thrashing), paraleliza em SSD/NVMe. (default, recomendado)
	//   "serial"    → sempre uma cópia por vez (qualquer disco).
	//   "parallel"  → sempre em paralelo até MaxConcurrentTransfers (ignora a
	//                 detecção de HDD; útil p/ RAID/NVMe-cache onde seek não dói).
	// Lido AO VIVO a cada promote (UI/yaml alteram sem reiniciar).
	TransferConcurrencyMode string              `yaml:"transfer_concurrency_mode"`
	PromoteDirs             []PromoteDir        `yaml:"promote_dirs"` // additional promote destinations (name + path)
	BandwidthSchedules      []BandwidthSchedule `yaml:"bandwidth_schedules"`

	// ── Performance / hardware tuning (0/"" = usar default; aplicado no streamer) ──
	// Banda: caps de peer em bytes/seg; 0 = ilimitado. Aplicados AO VIVO via
	// Streamer.SetRateLimits (não exigem reinício).
	MaxDownloadRate int64 `yaml:"max_download_rate"`
	MaxUploadRate   int64 `yaml:"max_upload_rate"`
	// ReadaheadMB é o buffer de leitura à frente por sessão de streaming. 0 → 32.
	// Mais readahead = playback mais suave em rede/disco lento, porém mais RAM por
	// stream simultâneo. Aplicado ao vivo (vale no próximo play).
	ReadaheadMB int `yaml:"readahead_mb"`
	// StorageBackend escolhe como os pieces são abertos no disco: "file" (padrão,
	// grava direto) ou "mmap" (mapeia em memória via page cache; random-access/seek
	// mais rápido). Mudança exige REINÍCIO (o anacrolix lê isso na construção).
	StorageBackend string `yaml:"storage_backend"`
	// Tuning de peers/CPU — todos exigem REINÍCIO. 0 = default da lib anacrolix
	// (conns=50, half-open=25, peersHighWater=500, pieceHashers=2).
	MaxConnsPerTorrent int `yaml:"max_conns_per_torrent"`
	HalfOpenConns      int `yaml:"half_open_conns"`
	PeersHighWater     int `yaml:"peers_high_water"`
	PieceHashers       int `yaml:"piece_hashers"`
	// HLSVODMode controla o caminho de VOD finito (seekbar) no HLS transcodado:
	// "all" (padrão: VOD para todos, inclusive HLS nativo do Safari), "hlsjs"
	// (VOD apenas para clientes não-Safari — rollback se o Safari regredir),
	// "off" (só EVENT/live). Permite ajustar sem recompilar; rollback
	// instantâneo voltando para "hlsjs" ou "off".
	// Env: JACKUI_HLS_VOD_MODE. Aplicado ao vivo (vale na próxima sessão HLS).
	HLSVODMode string `yaml:"hls_vod_mode"`
	// SeedTrackers lista substrings/hostnames de trackers cujos torrents devem
	// CONTINUAR seedando após o uso (não são dropados pelo idle reaper nem pelo
	// fim do stream), em vez do comportamento padrão de dropar. Casado
	// case-insensitive contra as announce URLs do torrent (ex.: "jackui").
	// Vazio = ninguém é mantido (comportamento atual). Aplicado ao vivo via
	// Streamer.SetSeedTrackers. Env: JACKUI_SEED_TRACKERS (CSV).
	SeedTrackers []string `yaml:"seed_trackers"`
}

type SubtitlesConfig

type SubtitlesConfig struct {
	OpenSubtitlesAPIKey   string `yaml:"opensubtitles_api_key"`
	OpenSubtitlesUsername string `yaml:"opensubtitles_username"`
	OpenSubtitlesPassword string `yaml:"opensubtitles_password"`
	CacheDir              string `yaml:"cache_dir"`
}

type TMDBConfig

type TMDBConfig struct {
	APIKey     string `yaml:"api_key"`      // empty disables enrichment (no posters)
	OMDbAPIKey string `yaml:"omdb_api_key"` // empty disables real IMDb ratings (falls back to TMDB vote)
}

Jump to

Keyboard shortcuts

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