Documentation
¶
Index ¶
- Constants
- func ActiveEnvOverrides() map[string]string
- func CheckWritable(path string) error
- func DefaultFreeModels(provider string) []string
- func EffectiveRPM(provider string, configRPM int) int
- func IsFreeGoogleModel(model string, free []string) bool
- type AIChainSlot
- type AIConfig
- type AIProvider
- type AuthConfig
- type BandwidthSchedule
- type Config
- type DownloadClient
- type DownloadsQueueConfig
- type ExternalConfig
- type ExternalMount
- type NotificationsConfig
- type PromoteDir
- type SMTPConfig
- type StreamConfig
- type SubtitlesConfig
- type TMDBConfig
Constants ¶
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 CheckWritable ¶
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 ¶
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 ¶
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 ¶
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 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"`
}
type DownloadClient ¶
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 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)
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"`
// HLSMediaRenditions liga as renditions EXT-X-MEDIA do master HLS (Phase 2
// M2b): faixas de áudio alternativas como TYPE=AUDIO (a/:track) e legendas de
// texto como TYPE=SUBTITLES (sub/:track, WebVTT). DEFAULT false (dark launch):
// o frontend precisa migrar pra hls.audioTrack (troca seamless, sem reload) e
// ser validado no Chrome/Safari antes de ligar — com false o master mantém o
// comportamento M2a (só STREAM-INF multi-resolução + ?audio via reload).
// Env: JACKUI_HLS_MEDIA_RENDITIONS (1/true).
HLSMediaRenditions bool `yaml:"hls_media_renditions"`
// 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"`
}