From b411d8ec63cb2567e63786e4b19fb36804bf5915 Mon Sep 17 00:00:00 2001 From: Jyn Date: Sat, 14 Feb 2026 06:22:10 +0700 Subject: [PATCH 1/3] load btsets from env --- server/settings/btsets.go | 205 +++++++++++++++++++++++++++++++++++++- 1 file changed, 204 insertions(+), 1 deletion(-) diff --git a/server/settings/btsets.go b/server/settings/btsets.go index 3829cbf96..71dbab5a4 100644 --- a/server/settings/btsets.go +++ b/server/settings/btsets.go @@ -4,8 +4,9 @@ import ( "encoding/json" "io" "io/fs" - + "os" "path/filepath" + "strconv" "strings" "server/log" @@ -123,6 +124,8 @@ func SetBTSets(sets *BTSets) { if sets.TorrentsSavePath == "" { sets.UseDisk = false } else if sets.UseDisk { + // apply environment overrides before persisting + applyEnvOverrides(sets) BTsets = sets go filepath.WalkDir(sets.TorrentsSavePath, func(path string, d fs.DirEntry, err error) error { @@ -168,6 +171,8 @@ func SetDefaultConfig() { ImageURL: "https://image.tmdb.org", ImageURLRu: "https://imagetmdb.com", } + // apply environment overrides so envs can change defaults + applyEnvOverrides(sets) BTsets = sets if !ReadOnly { buf, err := json.Marshal(BTsets) @@ -196,6 +201,8 @@ func loadBTSets() { ImageURLRu: "https://imagetmdb.com", } } + // apply environment overrides (envs take precedence over stored config) + applyEnvOverrides(BTsets) return } log.TLogln("Error unmarshal btsets", err) @@ -203,3 +210,199 @@ func loadBTSets() { // initialize defaults on error SetDefaultConfig() } + +// parse boolean-like env values +func parseBoolEnv(v string) (bool, bool) { + if v == "" { + return false, false + } + s := strings.ToLower(strings.TrimSpace(v)) + switch s { + case "1", "true", "yes", "on": + return true, true + case "0", "false", "no", "off": + return false, true + } + return false, false +} + +// applyEnvOverrides reads env vars prefixed with TORRSERVER_ and overrides fields +func applyEnvOverrides(sets *BTSets) { + if sets == nil { + return + } + + if v := os.Getenv("TORRSERVER_CACHESIZE"); v != "" { + if i, err := strconv.ParseInt(v, 10, 64); err == nil { + sets.CacheSize = i + } + } + if v := os.Getenv("TORRSERVER_READER_READ_AHEAD"); v != "" { + if i, err := strconv.Atoi(v); err == nil { + sets.ReaderReadAHead = i + } + } + if v := os.Getenv("TORRSERVER_PRELOAD_CACHE"); v != "" { + if i, err := strconv.Atoi(v); err == nil { + sets.PreloadCache = i + } + } + + if v, ok := parseBoolEnv(os.Getenv("TORRSERVER_USE_DISK")); ok { + sets.UseDisk = v + } + if v := os.Getenv("TORRSERVER_TORRENTS_SAVE_PATH"); v != "" { + sets.TorrentsSavePath = v + } + if v, ok := parseBoolEnv(os.Getenv("TORRSERVER_REMOVE_CACHE_ON_DROP")); ok { + sets.RemoveCacheOnDrop = v + } + + if v, ok := parseBoolEnv(os.Getenv("TORRSERVER_FORCE_ENCRYPT")); ok { + sets.ForceEncrypt = v + } + if v := os.Getenv("TORRSERVER_RETRACKERS_MODE"); v != "" { + if i, err := strconv.Atoi(v); err == nil { + sets.RetrackersMode = i + } + } + if v := os.Getenv("TORRSERVER_TORRENT_DISCONNECT_TIMEOUT"); v != "" { + if i, err := strconv.Atoi(v); err == nil { + sets.TorrentDisconnectTimeout = i + } + } + if v, ok := parseBoolEnv(os.Getenv("TORRSERVER_ENABLE_DEBUG")); ok { + sets.EnableDebug = v + } + + if v, ok := parseBoolEnv(os.Getenv("TORRSERVER_ENABLE_DLNA")); ok { + sets.EnableDLNA = v + } + if v := os.Getenv("TORRSERVER_FRIENDLY_NAME"); v != "" { + sets.FriendlyName = v + } + + if v, ok := parseBoolEnv(os.Getenv("TORRSERVER_ENABLE_RUTOR_SEARCH")); ok { + sets.EnableRutorSearch = v + } + + if v, ok := parseBoolEnv(os.Getenv("TORRSERVER_ENABLE_TORZNAB_SEARCH")); ok { + sets.EnableTorznabSearch = v + } + if v := os.Getenv("TORRSERVER_TORZNAB_URLS"); v != "" { + // try JSON first + var urls []TorznabConfig + if err := json.Unmarshal([]byte(v), &urls); err == nil { + sets.TorznabUrls = urls + } else { + // fallback: semicolon separated host|key|name entries + parts := strings.Split(v, ";") + var list []TorznabConfig + for _, p := range parts { + p = strings.TrimSpace(p) + if p == "" { + continue + } + fields := strings.Split(p, "|") + if len(fields) >= 2 { + cfg := TorznabConfig{Host: strings.TrimSpace(fields[0]), Key: strings.TrimSpace(fields[1])} + if len(fields) >= 3 { + cfg.Name = strings.TrimSpace(fields[2]) + } + list = append(list, cfg) + } + } + if len(list) > 0 { + sets.TorznabUrls = list + } + } + } + + // TMDB + if v := os.Getenv("TORRSERVER_TMDB_APIKEY"); v != "" { + sets.TMDBSettings.APIKey = v + } + if v := os.Getenv("TORRSERVER_TMDB_APIURL"); v != "" { + sets.TMDBSettings.APIURL = v + } + if v := os.Getenv("TORRSERVER_TMDB_IMAGEURL"); v != "" { + sets.TMDBSettings.ImageURL = v + } + if v := os.Getenv("TORRSERVER_TMDB_IMAGEURL_RU"); v != "" { + sets.TMDBSettings.ImageURLRu = v + } + + // BT config + if v, ok := parseBoolEnv(os.Getenv("TORRSERVER_ENABLE_IPV6")); ok { + sets.EnableIPv6 = v + } + if v, ok := parseBoolEnv(os.Getenv("TORRSERVER_DISABLE_TCP")); ok { + sets.DisableTCP = v + } + if v, ok := parseBoolEnv(os.Getenv("TORRSERVER_DISABLE_UTP")); ok { + sets.DisableUTP = v + } + if v, ok := parseBoolEnv(os.Getenv("TORRSERVER_DISABLE_UPNP")); ok { + sets.DisableUPNP = v + } + if v, ok := parseBoolEnv(os.Getenv("TORRSERVER_DISABLE_DHT")); ok { + sets.DisableDHT = v + } + if v, ok := parseBoolEnv(os.Getenv("TORRSERVER_DISABLE_PEX")); ok { + sets.DisablePEX = v + } + if v, ok := parseBoolEnv(os.Getenv("TORRSERVER_DISABLE_UPLOAD")); ok { + sets.DisableUpload = v + } + if v := os.Getenv("TORRSERVER_DOWNLOAD_RATE_LIMIT"); v != "" { + if i, err := strconv.Atoi(v); err == nil { + sets.DownloadRateLimit = i + } + } + if v := os.Getenv("TORRSERVER_UPLOAD_RATE_LIMIT"); v != "" { + if i, err := strconv.Atoi(v); err == nil { + sets.UploadRateLimit = i + } + } + if v := os.Getenv("TORRSERVER_CONNECTIONS_LIMIT"); v != "" { + if i, err := strconv.Atoi(v); err == nil { + sets.ConnectionsLimit = i + } + } + if v := os.Getenv("TORRSERVER_PEERS_LISTEN_PORT"); v != "" { + if i, err := strconv.Atoi(v); err == nil { + sets.PeersListenPort = i + } + } + + // HTTPS + if v := os.Getenv("TORRSERVER_SSL_PORT"); v != "" { + if i, err := strconv.Atoi(v); err == nil { + sets.SslPort = i + } + } + if v := os.Getenv("TORRSERVER_SSL_CERT"); v != "" { + sets.SslCert = v + } + if v := os.Getenv("TORRSERVER_SSL_KEY"); v != "" { + sets.SslKey = v + } + + // Reader + if v, ok := parseBoolEnv(os.Getenv("TORRSERVER_RESPONSIVE_MODE")); ok { + sets.ResponsiveMode = v + } + + // FS + if v, ok := parseBoolEnv(os.Getenv("TORRSERVER_SHOW_FS_ACTIVE_TORR")); ok { + sets.ShowFSActiveTorr = v + } + + // Storage preferences + if v, ok := parseBoolEnv(os.Getenv("TORRSERVER_STORE_SETTINGS_IN_JSON")); ok { + sets.StoreSettingsInJson = v + } + if v, ok := parseBoolEnv(os.Getenv("TORRSERVER_STORE_VIEWED_IN_JSON")); ok { + sets.StoreViewedInJson = v + } +} From d643d82e22ca9d455ae1eab2b148f063d7cb9f8b Mon Sep 17 00:00:00 2001 From: Jyn Date: Sat, 14 Feb 2026 06:36:46 +0700 Subject: [PATCH 2/3] change env prefix + readme --- README.md | 104 ++++++++++++++++++++++++++++++++++---- server/settings/btsets.go | 83 ++++++++++++++---------------- 2 files changed, 132 insertions(+), 55 deletions(-) diff --git a/README.md b/README.md index fdad058b6..f6266a34e 100644 --- a/README.md +++ b/README.md @@ -206,15 +206,57 @@ docker run --rm -d --name torrserver -v ~/ts:/opt/ts -p 8090:8090 ghcr.io/yourok #### Environments -- `TS_HTTPAUTH` - 1, and place auth file into `~/ts/config` folder for enabling basic auth -- `TS_RDB` - if 1, then the enabling `--rdb` flag -- `TS_DONTKILL` - if 1, then the enabling `--dontkill` flag -- `TS_PORT` - for changind default port to **5555** (example), also u need to change `-p 8090:8090` to `-p 5555:5555` (example) -- `TS_CONF_PATH` - for overriding torrserver config path inside container. Example `/opt/tsss` -- `TS_TORR_DIR` - for overriding torrents directory. Example `/opt/torr_files` -- `TS_LOG_PATH` - for overriding log path. Example `/opt/torrserver.log` -- `TS_PROXYURL` - set proxy URL for BitTorrent traffic (http, socks4, socks5, socks5h), example: socks5h://user:password@example.com:2080 -- `TS_PROXYMODE` - set proxy mode: "tracker" (only HTTP trackers, default), "peers" (only peer connections), or "full" (all traffic) +| Variable | Type | Default | Description | +|---|---:|---|---| +| `TS_HTTPAUTH` | bool/int | `0` | Enable basic HTTP auth (set `1` to enable) | +| `TS_RDB` | bool/int | `0` | Read-only DB mode (set `1` to enable) | +| `TS_DONTKILL` | bool/int | `0` | Do not kill server on signals (set `1` to enable) | +| `TS_PORT` | int | `8090` | Web server port | +| `TS_CONF_PATH` | string | `/opt/ts` | Path to config directory inside container | +| `TS_TORR_DIR` | string | `/opt/ts/torrents` | Path to torrents directory inside container | +| `TS_LOG_PATH` | string | `/opt/ts/torrserver.log` | Path to server log file inside container | +| `TS_PROXYURL` | string | `` | Proxy URL for BitTorrent traffic (http, socks4, socks5, socks5h) | +| `TS_PROXYMODE` | string | `tracker` | Proxy mode: `tracker`, `peers`, or `full` | +| `TS_TG` | string | `` | Telegram bot token (same as `--tg`) | +| `TS_BTSETS_CACHESIZE` | int (bytes) | `67108864` | Cache size in bytes (default 64MB) | +| `TS_BTSETS_READER_READ_AHEAD` | int (%) | `95` | Reader read-ahead percent (5-100) | +| `TS_BTSETS_PRELOAD_CACHE` | int (%) | `50` | Preload cache percent (0-100) | +| `TS_BTSETS_USE_DISK` | bool | `false` | Enable disk-backed cache | +| `TS_BTSETS_TORRENTS_SAVE_PATH` | string | `` | Path to torrents/cache directory inside container | +| `TS_BTSETS_REMOVE_CACHE_ON_DROP` | bool | `false` | Remove cached files when torrent dropped | +| `TS_BTSETS_FORCE_ENCRYPT` | bool | `false` | Force encryption for BitTorrent connections | +| `TS_BTSETS_RETRACKERS_MODE` | int | `1` | Retrackers handling: `0`-don't add, `1`-add, `2`-remove, `3`-replace | +| `TS_BTSETS_TORRENT_DISCONNECT_TIMEOUT` | int (s) | `30` | Torrent disconnect timeout in seconds | +| `TS_BTSETS_ENABLE_DEBUG` | bool | `false` | Enable debug logging | +| `TS_BTSETS_ENABLE_DLNA` | bool | `false` | Enable built-in DLNA server | +| `TS_BTSETS_FRIENDLY_NAME` | string | `` | DLNA friendly name | +| `TS_BTSETS_ENABLE_RUTOR_SEARCH` | bool | `false` | Enable Rutor search integration | +| `TS_BTSETS_ENABLE_TORZNAB_SEARCH` | bool | `false` | Enable Torznab search integration | +| `TS_BTSETS_TORZNAB_URLS` | json or string | `[]` | Torznab endpoints (JSON array or `host|key|name;...`) | +| `TS_BTSETS_TMDB_APIKEY` | string | `` | TMDB API key | +| `TS_BTSETS_TMDB_APIURL` | string | `https://api.themoviedb.org` | TMDB API base URL | +| `TS_BTSETS_TMDB_IMAGEURL` | string | `https://image.tmdb.org` | TMDB image base URL | +| `TS_BTSETS_TMDB_IMAGEURL_RU` | string | `https://imagetmdb.com` | TMDB image URL for RU users | +| `TS_BTSETS_ENABLE_IPV6` | bool | `false` | Enable IPv6 support for BT connections | +| `TS_BTSETS_DISABLE_TCP` | bool | `false` | Disable TCP transports | +| `TS_BTSETS_DISABLE_UTP` | bool | `false` | Disable uTP transports | +| `TS_BTSETS_DISABLE_UPNP` | bool | `false` | Disable UPnP | +| `TS_BTSETS_DISABLE_DHT` | bool | `false` | Disable DHT | +| `TS_BTSETS_DISABLE_PEX` | bool | `false` | Disable PEX | +| `TS_BTSETS_DISABLE_UPLOAD` | bool | `false` | Disable uploading to peers | +| `TS_BTSETS_DOWNLOAD_RATE_LIMIT` | int (kb) | `0` | Download rate limit in KB/s (0 = unlimited) | +| `TS_BTSETS_UPLOAD_RATE_LIMIT` | int (kb) | `0` | Upload rate limit in KB/s (0 = unlimited) | +| `TS_BTSETS_CONNECTIONS_LIMIT` | int | `25` | Max simultaneous connections | +| `TS_BTSETS_PEERS_LISTEN_PORT` | int | `` | Listening port for peers (if set) | +| `TS_BTSETS_SSL_PORT` | int | `0` | HTTPS port (if 0, not set) | +| `TS_BTSETS_SSL_CERT` | string | `` | Path to SSL certificate inside container | +| `TS_BTSETS_SSL_KEY` | string | `` | Path to SSL key inside container | +| `TS_BTSETS_RESPONSIVE_MODE` | bool | `true` | Enable responsive reader mode | +| `TS_BTSETS_SHOW_FS_ACTIVE_TORR` | bool | `true` | Show FS active torrents in UI | +| `TS_BTSETS_STORE_SETTINGS_IN_JSON` | bool | `true` | Store settings in JSON format | +| `TS_BTSETS_STORE_VIEWED_IN_JSON` | bool | `true` | Store viewed list in JSON format | + +Use these variables in your `docker run` or `docker-compose.yml` under `environment:` (they take precedence over stored DB settings). Example with full overrided command (on default values): @@ -249,6 +291,50 @@ services: ``` + #### Docker Compose: environment variables reference + + | Variable | Type | Default | Description | + |---|---:|---|---| + | `TS_BTSETS_CACHESIZE` | int (bytes) | `67108864` | Cache size in bytes (default 64MB) | + | `TS_BTSETS_READER_READ_AHEAD` | int (%) | `95` | Reader read-ahead percent (5-100) | + | `TS_BTSETS_PRELOAD_CACHE` | int (%) | `50` | Preload cache percent (0-100) | + | `TS_BTSETS_USE_DISK` | bool | `false` | Enable disk-backed cache | + | `TS_BTSETS_TORRENTS_SAVE_PATH` | string | `` | Path to torrents/cache directory inside container | + | `TS_BTSETS_REMOVE_CACHE_ON_DROP` | bool | `false` | Remove cached files when torrent dropped | + | `TS_BTSETS_FORCE_ENCRYPT` | bool | `false` | Force encryption for BitTorrent connections | + | `TS_BTSETS_RETRACKERS_MODE` | int | `1` | Retrackers handling: `0`-don't add, `1`-add, `2`-remove, `3`-replace | + | `TS_BTSETS_TORRENT_DISCONNECT_TIMEOUT` | int (s) | `30` | Torrent disconnect timeout in seconds | + | `TS_BTSETS_ENABLE_DEBUG` | bool | `false` | Enable debug logging | + | `TS_BTSETS_ENABLE_DLNA` | bool | `false` | Enable built-in DLNA server | + | `TS_BTSETS_FRIENDLY_NAME` | string | `` | DLNA friendly name | + | `TS_BTSETS_ENABLE_RUTOR_SEARCH` | bool | `false` | Enable Rutor search integration | + | `TS_BTSETS_ENABLE_TORZNAB_SEARCH` | bool | `false` | Enable Torznab search integration | + | `TS_BTSETS_TORZNAB_URLS` | json or string | `[]` | Torznab endpoints (JSON array or `host|key|name;...`) | + | `TS_BTSETS_TMDB_APIKEY` | string | `` | TMDB API key | + | `TS_BTSETS_TMDB_APIURL` | string | `https://api.themoviedb.org` | TMDB API base URL | + | `TS_BTSETS_TMDB_IMAGEURL` | string | `https://image.tmdb.org` | TMDB image base URL | + | `TS_BTSETS_TMDB_IMAGEURL_RU` | string | `https://imagetmdb.com` | TMDB image URL for RU users | + | `TS_BTSETS_ENABLE_IPV6` | bool | `false` | Enable IPv6 support for BT connections | + | `TS_BTSETS_DISABLE_TCP` | bool | `false` | Disable TCP transports | + | `TS_BTSETS_DISABLE_UTP` | bool | `false` | Disable uTP transports | + | `TS_BTSETS_DISABLE_UPNP` | bool | `false` | Disable UPnP | + | `TS_BTSETS_DISABLE_DHT` | bool | `false` | Disable DHT | + | `TS_BTSETS_DISABLE_PEX` | bool | `false` | Disable PEX | + | `TS_BTSETS_DISABLE_UPLOAD` | bool | `false` | Disable uploading to peers | + | `TS_BTSETS_DOWNLOAD_RATE_LIMIT` | int (kb) | `0` | Download rate limit in KB/s (0 = unlimited) | + | `TS_BTSETS_UPLOAD_RATE_LIMIT` | int (kb) | `0` | Upload rate limit in KB/s (0 = unlimited) | + | `TS_BTSETS_CONNECTIONS_LIMIT` | int | `25` | Max simultaneous connections | + | `TS_BTSETS_PEERS_LISTEN_PORT` | int | `` | Listening port for peers (if set) | + | `TS_BTSETS_SSL_PORT` | int | `0` | HTTPS port (if 0, not set) | + | `TS_BTSETS_SSL_CERT` | string | `` | Path to SSL certificate inside container | + | `TS_BTSETS_SSL_KEY` | string | `` | Path to SSL key inside container | + | `TS_BTSETS_RESPONSIVE_MODE` | bool | `true` | Enable responsive reader mode | + | `TS_BTSETS_SHOW_FS_ACTIVE_TORR` | bool | `true` | Show FS active torrents in UI | + | `TS_BTSETS_STORE_SETTINGS_IN_JSON` | bool | `true` | Store settings in JSON format | + | `TS_BTSETS_STORE_VIEWED_IN_JSON` | bool | `true` | Store viewed list in JSON format | + + Use these variables in your `docker-compose.yml` under `environment:` (they take precedence over stored DB settings). + ### Smart TV (using Media Station X) 1. Install **Media Station X** on your Smart TV (see [platform support](https://msx.benzac.de/info/?tab=PlatformSupport)) diff --git a/server/settings/btsets.go b/server/settings/btsets.go index 71dbab5a4..7aafa9cc0 100644 --- a/server/settings/btsets.go +++ b/server/settings/btsets.go @@ -232,64 +232,60 @@ func applyEnvOverrides(sets *BTSets) { return } - if v := os.Getenv("TORRSERVER_CACHESIZE"); v != "" { + if v := os.Getenv("TS_BTSETS_CACHESIZE"); v != "" { if i, err := strconv.ParseInt(v, 10, 64); err == nil { sets.CacheSize = i } } - if v := os.Getenv("TORRSERVER_READER_READ_AHEAD"); v != "" { + if v := os.Getenv("TS_BTSETS_READER_READ_AHEAD"); v != "" { if i, err := strconv.Atoi(v); err == nil { sets.ReaderReadAHead = i } } - if v := os.Getenv("TORRSERVER_PRELOAD_CACHE"); v != "" { + if v := os.Getenv("TS_BTSETS_PRELOAD_CACHE"); v != "" { if i, err := strconv.Atoi(v); err == nil { sets.PreloadCache = i } } - if v, ok := parseBoolEnv(os.Getenv("TORRSERVER_USE_DISK")); ok { + if v, ok := parseBoolEnv(os.Getenv("TS_BTSETS_USE_DISK")); ok { sets.UseDisk = v } - if v := os.Getenv("TORRSERVER_TORRENTS_SAVE_PATH"); v != "" { + if v := os.Getenv("TS_BTSETS_TORRENTS_SAVE_PATH"); v != "" { sets.TorrentsSavePath = v } - if v, ok := parseBoolEnv(os.Getenv("TORRSERVER_REMOVE_CACHE_ON_DROP")); ok { + if v, ok := parseBoolEnv(os.Getenv("TS_BTSETS_REMOVE_CACHE_ON_DROP")); ok { sets.RemoveCacheOnDrop = v } - - if v, ok := parseBoolEnv(os.Getenv("TORRSERVER_FORCE_ENCRYPT")); ok { + if v, ok := parseBoolEnv(os.Getenv("TS_BTSETS_FORCE_ENCRYPT")); ok { sets.ForceEncrypt = v } - if v := os.Getenv("TORRSERVER_RETRACKERS_MODE"); v != "" { + if v := os.Getenv("TS_BTSETS_RETRACKERS_MODE"); v != "" { if i, err := strconv.Atoi(v); err == nil { sets.RetrackersMode = i } } - if v := os.Getenv("TORRSERVER_TORRENT_DISCONNECT_TIMEOUT"); v != "" { + if v := os.Getenv("TS_BTSETS_TORRENT_DISCONNECT_TIMEOUT"); v != "" { if i, err := strconv.Atoi(v); err == nil { sets.TorrentDisconnectTimeout = i } } - if v, ok := parseBoolEnv(os.Getenv("TORRSERVER_ENABLE_DEBUG")); ok { + if v, ok := parseBoolEnv(os.Getenv("TS_BTSETS_ENABLE_DEBUG")); ok { sets.EnableDebug = v } - - if v, ok := parseBoolEnv(os.Getenv("TORRSERVER_ENABLE_DLNA")); ok { + if v, ok := parseBoolEnv(os.Getenv("TS_BTSETS_ENABLE_DLNA")); ok { sets.EnableDLNA = v } - if v := os.Getenv("TORRSERVER_FRIENDLY_NAME"); v != "" { + if v := os.Getenv("TS_BTSETS_FRIENDLY_NAME"); v != "" { sets.FriendlyName = v } - - if v, ok := parseBoolEnv(os.Getenv("TORRSERVER_ENABLE_RUTOR_SEARCH")); ok { + if v, ok := parseBoolEnv(os.Getenv("TS_BTSETS_ENABLE_RUTOR_SEARCH")); ok { sets.EnableRutorSearch = v } - - if v, ok := parseBoolEnv(os.Getenv("TORRSERVER_ENABLE_TORZNAB_SEARCH")); ok { + if v, ok := parseBoolEnv(os.Getenv("TS_BTSETS_ENABLE_TORZNAB_SEARCH")); ok { sets.EnableTorznabSearch = v } - if v := os.Getenv("TORRSERVER_TORZNAB_URLS"); v != "" { + if v := os.Getenv("TS_BTSETS_TORZNAB_URLS"); v != "" { // try JSON first var urls []TorznabConfig if err := json.Unmarshal([]byte(v), &urls); err == nil { @@ -319,90 +315,85 @@ func applyEnvOverrides(sets *BTSets) { } // TMDB - if v := os.Getenv("TORRSERVER_TMDB_APIKEY"); v != "" { + if v := os.Getenv("TS_BTSETS_TMDB_APIKEY"); v != "" { sets.TMDBSettings.APIKey = v } - if v := os.Getenv("TORRSERVER_TMDB_APIURL"); v != "" { + if v := os.Getenv("TS_BTSETS_TMDB_APIURL"); v != "" { sets.TMDBSettings.APIURL = v } - if v := os.Getenv("TORRSERVER_TMDB_IMAGEURL"); v != "" { + if v := os.Getenv("TS_BTSETS_TMDB_IMAGEURL"); v != "" { sets.TMDBSettings.ImageURL = v } - if v := os.Getenv("TORRSERVER_TMDB_IMAGEURL_RU"); v != "" { + if v := os.Getenv("TS_BTSETS_TMDB_IMAGEURL_RU"); v != "" { sets.TMDBSettings.ImageURLRu = v } - // BT config - if v, ok := parseBoolEnv(os.Getenv("TORRSERVER_ENABLE_IPV6")); ok { + if v, ok := parseBoolEnv(os.Getenv("TS_BTSETS_ENABLE_IPV6")); ok { sets.EnableIPv6 = v } - if v, ok := parseBoolEnv(os.Getenv("TORRSERVER_DISABLE_TCP")); ok { + if v, ok := parseBoolEnv(os.Getenv("TS_BTSETS_DISABLE_TCP")); ok { sets.DisableTCP = v } - if v, ok := parseBoolEnv(os.Getenv("TORRSERVER_DISABLE_UTP")); ok { + if v, ok := parseBoolEnv(os.Getenv("TS_BTSETS_DISABLE_UTP")); ok { sets.DisableUTP = v } - if v, ok := parseBoolEnv(os.Getenv("TORRSERVER_DISABLE_UPNP")); ok { + if v, ok := parseBoolEnv(os.Getenv("TS_BTSETS_DISABLE_UPNP")); ok { sets.DisableUPNP = v } - if v, ok := parseBoolEnv(os.Getenv("TORRSERVER_DISABLE_DHT")); ok { + if v, ok := parseBoolEnv(os.Getenv("TS_BTSETS_DISABLE_DHT")); ok { sets.DisableDHT = v } - if v, ok := parseBoolEnv(os.Getenv("TORRSERVER_DISABLE_PEX")); ok { + if v, ok := parseBoolEnv(os.Getenv("TS_BTSETS_DISABLE_PEX")); ok { sets.DisablePEX = v } - if v, ok := parseBoolEnv(os.Getenv("TORRSERVER_DISABLE_UPLOAD")); ok { + if v, ok := parseBoolEnv(os.Getenv("TS_BTSETS_DISABLE_UPLOAD")); ok { sets.DisableUpload = v } - if v := os.Getenv("TORRSERVER_DOWNLOAD_RATE_LIMIT"); v != "" { + if v := os.Getenv("TS_BTSETS_DOWNLOAD_RATE_LIMIT"); v != "" { if i, err := strconv.Atoi(v); err == nil { sets.DownloadRateLimit = i } } - if v := os.Getenv("TORRSERVER_UPLOAD_RATE_LIMIT"); v != "" { + if v := os.Getenv("TS_BTSETS_UPLOAD_RATE_LIMIT"); v != "" { if i, err := strconv.Atoi(v); err == nil { sets.UploadRateLimit = i } } - if v := os.Getenv("TORRSERVER_CONNECTIONS_LIMIT"); v != "" { + if v := os.Getenv("TS_BTSETS_CONNECTIONS_LIMIT"); v != "" { if i, err := strconv.Atoi(v); err == nil { sets.ConnectionsLimit = i } } - if v := os.Getenv("TORRSERVER_PEERS_LISTEN_PORT"); v != "" { + if v := os.Getenv("TS_BTSETS_PEERS_LISTEN_PORT"); v != "" { if i, err := strconv.Atoi(v); err == nil { sets.PeersListenPort = i } } - // HTTPS - if v := os.Getenv("TORRSERVER_SSL_PORT"); v != "" { + if v := os.Getenv("TS_BTSETS_SSL_PORT"); v != "" { if i, err := strconv.Atoi(v); err == nil { sets.SslPort = i } } - if v := os.Getenv("TORRSERVER_SSL_CERT"); v != "" { + if v := os.Getenv("TS_BTSETS_SSL_CERT"); v != "" { sets.SslCert = v } - if v := os.Getenv("TORRSERVER_SSL_KEY"); v != "" { + if v := os.Getenv("TS_BTSETS_SSL_KEY"); v != "" { sets.SslKey = v } - // Reader - if v, ok := parseBoolEnv(os.Getenv("TORRSERVER_RESPONSIVE_MODE")); ok { + if v, ok := parseBoolEnv(os.Getenv("TS_BTSETS_RESPONSIVE_MODE")); ok { sets.ResponsiveMode = v } - // FS - if v, ok := parseBoolEnv(os.Getenv("TORRSERVER_SHOW_FS_ACTIVE_TORR")); ok { + if v, ok := parseBoolEnv(os.Getenv("TS_BTSETS_SHOW_FS_ACTIVE_TORR")); ok { sets.ShowFSActiveTorr = v } - // Storage preferences - if v, ok := parseBoolEnv(os.Getenv("TORRSERVER_STORE_SETTINGS_IN_JSON")); ok { + if v, ok := parseBoolEnv(os.Getenv("TS_BTSETS_STORE_SETTINGS_IN_JSON")); ok { sets.StoreSettingsInJson = v } - if v, ok := parseBoolEnv(os.Getenv("TORRSERVER_STORE_VIEWED_IN_JSON")); ok { + if v, ok := parseBoolEnv(os.Getenv("TS_BTSETS_STORE_VIEWED_IN_JSON")); ok { sets.StoreViewedInJson = v } } From 6b9b42e4550d994feecb905c72e32b2320d23577 Mon Sep 17 00:00:00 2001 From: Jyn Date: Sat, 14 Feb 2026 06:52:00 +0700 Subject: [PATCH 3/3] fix: readme double env desc --- README.md | 43 ------------------------------------------- 1 file changed, 43 deletions(-) diff --git a/README.md b/README.md index f6266a34e..98a2ee68a 100644 --- a/README.md +++ b/README.md @@ -291,49 +291,6 @@ services: ``` - #### Docker Compose: environment variables reference - - | Variable | Type | Default | Description | - |---|---:|---|---| - | `TS_BTSETS_CACHESIZE` | int (bytes) | `67108864` | Cache size in bytes (default 64MB) | - | `TS_BTSETS_READER_READ_AHEAD` | int (%) | `95` | Reader read-ahead percent (5-100) | - | `TS_BTSETS_PRELOAD_CACHE` | int (%) | `50` | Preload cache percent (0-100) | - | `TS_BTSETS_USE_DISK` | bool | `false` | Enable disk-backed cache | - | `TS_BTSETS_TORRENTS_SAVE_PATH` | string | `` | Path to torrents/cache directory inside container | - | `TS_BTSETS_REMOVE_CACHE_ON_DROP` | bool | `false` | Remove cached files when torrent dropped | - | `TS_BTSETS_FORCE_ENCRYPT` | bool | `false` | Force encryption for BitTorrent connections | - | `TS_BTSETS_RETRACKERS_MODE` | int | `1` | Retrackers handling: `0`-don't add, `1`-add, `2`-remove, `3`-replace | - | `TS_BTSETS_TORRENT_DISCONNECT_TIMEOUT` | int (s) | `30` | Torrent disconnect timeout in seconds | - | `TS_BTSETS_ENABLE_DEBUG` | bool | `false` | Enable debug logging | - | `TS_BTSETS_ENABLE_DLNA` | bool | `false` | Enable built-in DLNA server | - | `TS_BTSETS_FRIENDLY_NAME` | string | `` | DLNA friendly name | - | `TS_BTSETS_ENABLE_RUTOR_SEARCH` | bool | `false` | Enable Rutor search integration | - | `TS_BTSETS_ENABLE_TORZNAB_SEARCH` | bool | `false` | Enable Torznab search integration | - | `TS_BTSETS_TORZNAB_URLS` | json or string | `[]` | Torznab endpoints (JSON array or `host|key|name;...`) | - | `TS_BTSETS_TMDB_APIKEY` | string | `` | TMDB API key | - | `TS_BTSETS_TMDB_APIURL` | string | `https://api.themoviedb.org` | TMDB API base URL | - | `TS_BTSETS_TMDB_IMAGEURL` | string | `https://image.tmdb.org` | TMDB image base URL | - | `TS_BTSETS_TMDB_IMAGEURL_RU` | string | `https://imagetmdb.com` | TMDB image URL for RU users | - | `TS_BTSETS_ENABLE_IPV6` | bool | `false` | Enable IPv6 support for BT connections | - | `TS_BTSETS_DISABLE_TCP` | bool | `false` | Disable TCP transports | - | `TS_BTSETS_DISABLE_UTP` | bool | `false` | Disable uTP transports | - | `TS_BTSETS_DISABLE_UPNP` | bool | `false` | Disable UPnP | - | `TS_BTSETS_DISABLE_DHT` | bool | `false` | Disable DHT | - | `TS_BTSETS_DISABLE_PEX` | bool | `false` | Disable PEX | - | `TS_BTSETS_DISABLE_UPLOAD` | bool | `false` | Disable uploading to peers | - | `TS_BTSETS_DOWNLOAD_RATE_LIMIT` | int (kb) | `0` | Download rate limit in KB/s (0 = unlimited) | - | `TS_BTSETS_UPLOAD_RATE_LIMIT` | int (kb) | `0` | Upload rate limit in KB/s (0 = unlimited) | - | `TS_BTSETS_CONNECTIONS_LIMIT` | int | `25` | Max simultaneous connections | - | `TS_BTSETS_PEERS_LISTEN_PORT` | int | `` | Listening port for peers (if set) | - | `TS_BTSETS_SSL_PORT` | int | `0` | HTTPS port (if 0, not set) | - | `TS_BTSETS_SSL_CERT` | string | `` | Path to SSL certificate inside container | - | `TS_BTSETS_SSL_KEY` | string | `` | Path to SSL key inside container | - | `TS_BTSETS_RESPONSIVE_MODE` | bool | `true` | Enable responsive reader mode | - | `TS_BTSETS_SHOW_FS_ACTIVE_TORR` | bool | `true` | Show FS active torrents in UI | - | `TS_BTSETS_STORE_SETTINGS_IN_JSON` | bool | `true` | Store settings in JSON format | - | `TS_BTSETS_STORE_VIEWED_IN_JSON` | bool | `true` | Store viewed list in JSON format | - - Use these variables in your `docker-compose.yml` under `environment:` (they take precedence over stored DB settings). ### Smart TV (using Media Station X)