@muhammedaksam/easiarr 1.4.0 → 1.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. package/dist/index.js +29837 -0
  2. package/package.json +15 -15
  3. package/src/VersionInfo.ts +0 -12
  4. package/src/api/arr-api.ts +0 -521
  5. package/src/api/auto-setup-types.ts +0 -64
  6. package/src/api/base-api.ts +0 -216
  7. package/src/api/bazarr-api.ts +0 -297
  8. package/src/api/cloudflare-api.ts +0 -493
  9. package/src/api/custom-format-api.ts +0 -224
  10. package/src/api/grafana-api.ts +0 -230
  11. package/src/api/heimdall-api.ts +0 -141
  12. package/src/api/homarr-api.ts +0 -209
  13. package/src/api/huntarr-api.ts +0 -457
  14. package/src/api/index.ts +0 -9
  15. package/src/api/jellyfin-api.ts +0 -389
  16. package/src/api/jellyseerr-api.ts +0 -559
  17. package/src/api/maintainerr-api.ts +0 -461
  18. package/src/api/naming-config.ts +0 -101
  19. package/src/api/overseerr-api.ts +0 -392
  20. package/src/api/plex-api.ts +0 -308
  21. package/src/api/portainer-api.ts +0 -374
  22. package/src/api/profilarr-api.ts +0 -391
  23. package/src/api/prowlarr-api.ts +0 -488
  24. package/src/api/qbittorrent-api.ts +0 -300
  25. package/src/api/quality-profile-api.ts +0 -272
  26. package/src/api/tautulli-api.ts +0 -244
  27. package/src/api/uptime-kuma-api.ts +0 -343
  28. package/src/apps/categories.ts +0 -14
  29. package/src/apps/index.ts +0 -2
  30. package/src/apps/registry.ts +0 -1275
  31. package/src/compose/caddy-config.ts +0 -130
  32. package/src/compose/generator.ts +0 -287
  33. package/src/compose/index.ts +0 -7
  34. package/src/compose/templates.ts +0 -78
  35. package/src/compose/traefik-config.ts +0 -187
  36. package/src/config/bookmarks-generator.ts +0 -160
  37. package/src/config/defaults.ts +0 -37
  38. package/src/config/homepage-config.ts +0 -381
  39. package/src/config/index.ts +0 -6
  40. package/src/config/manager.ts +0 -150
  41. package/src/config/recyclarr-config.ts +0 -181
  42. package/src/config/schema.ts +0 -310
  43. package/src/config/slskd-config.ts +0 -86
  44. package/src/config/soularr-config.ts +0 -105
  45. package/src/config/trash-quality-definitions.ts +0 -213
  46. package/src/data/lidarr-custom-formats.ts +0 -127
  47. package/src/data/trash-profiles.ts +0 -333
  48. package/src/docker/client.ts +0 -312
  49. package/src/docker/index.ts +0 -18
  50. package/src/index.ts +0 -77
  51. package/src/setup/actions/arr-common.ts +0 -307
  52. package/src/setup/actions/dashboards.ts +0 -79
  53. package/src/setup/actions/download-clients.ts +0 -54
  54. package/src/setup/actions/jellyseerr.ts +0 -331
  55. package/src/setup/actions/media-servers.ts +0 -68
  56. package/src/setup/actions/monitoring.ts +0 -120
  57. package/src/setup/actions/prowlarr.ts +0 -137
  58. package/src/setup/actions/utilities.ts +0 -490
  59. package/src/setup/index.ts +0 -78
  60. package/src/setup/types.ts +0 -144
  61. package/src/structure/manager.ts +0 -129
  62. package/src/ui/App.ts +0 -111
  63. package/src/ui/components/ApplicationSelector.ts +0 -275
  64. package/src/ui/components/CredentialsForm.ts +0 -180
  65. package/src/ui/components/DownloadClientForm.ts +0 -114
  66. package/src/ui/components/FileEditor.ts +0 -91
  67. package/src/ui/components/FooterHint.ts +0 -119
  68. package/src/ui/components/PageLayout.ts +0 -160
  69. package/src/ui/components/UpdateNotification.ts +0 -102
  70. package/src/ui/index.ts +0 -7
  71. package/src/ui/screens/AdvancedSettings.ts +0 -188
  72. package/src/ui/screens/ApiKeyViewer.ts +0 -511
  73. package/src/ui/screens/AppConfigurator.ts +0 -543
  74. package/src/ui/screens/AppManager.ts +0 -284
  75. package/src/ui/screens/ContainerControl.ts +0 -581
  76. package/src/ui/screens/LogsViewer.ts +0 -478
  77. package/src/ui/screens/MainMenu.ts +0 -299
  78. package/src/ui/screens/MonitorDashboard.ts +0 -881
  79. package/src/ui/screens/SecretsEditor.ts +0 -216
  80. package/src/ui/screens/SettingsScreen.ts +0 -633
  81. package/src/ui/screens/index.ts +0 -22
  82. package/src/ui/screens/setup/BaseAppSetupScreen.ts +0 -375
  83. package/src/ui/screens/setup/CloudflaredSetup.ts +0 -460
  84. package/src/ui/screens/setup/FullAutoSetup.ts +0 -766
  85. package/src/ui/screens/setup/HomepageSetup.ts +0 -165
  86. package/src/ui/screens/setup/JellyfinSetup.ts +0 -328
  87. package/src/ui/screens/setup/JellyseerrSetup.ts +0 -242
  88. package/src/ui/screens/setup/ProwlarrSetup.ts +0 -500
  89. package/src/ui/screens/setup/QBittorrentSetup.ts +0 -221
  90. package/src/ui/screens/setup/QuickSetup.ts +0 -1169
  91. package/src/ui/screens/setup/RecyclarrSetup.ts +0 -270
  92. package/src/ui/screens/setup/TRaSHProfileSetup.ts +0 -381
  93. package/src/utils/arch.ts +0 -78
  94. package/src/utils/browser.ts +0 -27
  95. package/src/utils/categories.ts +0 -61
  96. package/src/utils/debug.ts +0 -84
  97. package/src/utils/env.ts +0 -138
  98. package/src/utils/index.ts +0 -8
  99. package/src/utils/logs.ts +0 -119
  100. package/src/utils/migrations/1765626338_rename_env_variables.ts +0 -102
  101. package/src/utils/migrations/1765707135_rename_easiarr_status.ts +0 -91
  102. package/src/utils/migrations/1765732722_remove_cloudflare_dns_api_token.ts +0 -45
  103. package/src/utils/migrations/1769515650_migrate_to_xdg.ts +0 -114
  104. package/src/utils/migrations.ts +0 -165
  105. package/src/utils/password.ts +0 -42
  106. package/src/utils/paths.ts +0 -33
  107. package/src/utils/unraid.ts +0 -103
  108. package/src/utils/update-checker.ts +0 -210
  109. package/src/utils/url-utils.ts +0 -38
@@ -1,150 +0,0 @@
1
- /**
2
- * Configuration Manager
3
- * Handles reading and writing config to $XDG_CONFIG_HOME/easiarr/
4
- */
5
-
6
- import { existsSync } from "node:fs"
7
- import { copyFile, mkdir, readFile, writeFile } from "node:fs/promises"
8
- import { homedir } from "node:os"
9
- import { join } from "node:path"
10
-
11
- import type { EasiarrConfig } from "./schema"
12
- import { debugLog } from "~/utils/debug"
13
- import { VersionInfo } from "~/VersionInfo"
14
- import { detectGid, detectTimezone, detectUid } from "./defaults"
15
- import { DEFAULT_CONFIG } from "./schema"
16
-
17
- const CONFIG_DIR_NAME = "easiarr"
18
- const CONFIG_FILE_NAME = "config.json"
19
- const BACKUP_DIR_NAME = "backups"
20
-
21
- export function getConfigDir(): string {
22
- const xdgConfigHome = process.env.XDG_CONFIG_HOME || join(homedir(), ".config")
23
- return join(xdgConfigHome, CONFIG_DIR_NAME)
24
- }
25
-
26
- export function getConfigPath(): string {
27
- return join(getConfigDir(), CONFIG_FILE_NAME)
28
- }
29
-
30
- export function getBackupDir(): string {
31
- return join(getConfigDir(), BACKUP_DIR_NAME)
32
- }
33
-
34
- export function getComposePath(): string {
35
- return join(getConfigDir(), "docker-compose.yml")
36
- }
37
-
38
- export async function ensureConfigDir(): Promise<void> {
39
- const configDir = getConfigDir()
40
- const backupDir = getBackupDir()
41
-
42
- if (!existsSync(configDir)) {
43
- await mkdir(configDir, { recursive: true })
44
- }
45
-
46
- if (!existsSync(backupDir)) {
47
- await mkdir(backupDir, { recursive: true })
48
- }
49
- }
50
-
51
- export async function configExists(): Promise<boolean> {
52
- return existsSync(getConfigPath())
53
- }
54
-
55
- /**
56
- * Migrate config to current version
57
- * Preserves user settings while adding new fields with defaults
58
- */
59
- function migrateConfig(oldConfig: Partial<EasiarrConfig>): EasiarrConfig {
60
- return {
61
- // Start with defaults for new fields
62
- ...DEFAULT_CONFIG,
63
- // Preserve all user settings
64
- ...oldConfig,
65
- // Always update version to current
66
- version: VersionInfo.version,
67
- // Ensure required fields have values
68
- umask: oldConfig.umask ?? "002",
69
- apps: oldConfig.apps ?? [],
70
- createdAt: oldConfig.createdAt ?? new Date().toISOString(),
71
- updatedAt: new Date().toISOString(),
72
- } as EasiarrConfig
73
- }
74
-
75
- export async function loadConfig(): Promise<EasiarrConfig | null> {
76
- const configPath = getConfigPath()
77
- debugLog("Config", `Loading config from ${configPath}`)
78
-
79
- if (!existsSync(configPath)) {
80
- debugLog("Config", "Config file not found")
81
- return null
82
- }
83
-
84
- try {
85
- const content = await readFile(configPath, "utf-8")
86
- let config = JSON.parse(content) as EasiarrConfig
87
- debugLog("Config", `Loaded config version ${config.version}`)
88
-
89
- // Auto-migrate if version differs from current package version
90
- if (config.version !== VersionInfo.version) {
91
- debugLog("Config", `Migrating config from ${config.version} to ${VersionInfo.version}`)
92
- config = migrateConfig(config)
93
- // Save migrated config (creates backup first)
94
- await saveConfig(config)
95
- }
96
-
97
- return config
98
- } catch (error) {
99
- debugLog("Config", `Failed to load config: ${error}`)
100
- console.error("Failed to load config:", error)
101
- return null
102
- }
103
- }
104
-
105
- export async function saveConfig(config: EasiarrConfig): Promise<void> {
106
- await ensureConfigDir()
107
-
108
- const configPath = getConfigPath()
109
- debugLog("Config", `Saving config to ${configPath}`)
110
-
111
- // Create backup if config already exists
112
- if (existsSync(configPath)) {
113
- await backupConfig()
114
- }
115
-
116
- // Update timestamp
117
- config.updatedAt = new Date().toISOString()
118
-
119
- await writeFile(configPath, JSON.stringify(config, null, 2), "utf-8")
120
- debugLog("Config", `Config saved (${config.apps.length} apps)`)
121
- }
122
-
123
- export async function backupConfig(): Promise<void> {
124
- const configPath = getConfigPath()
125
-
126
- if (!existsSync(configPath)) {
127
- return
128
- }
129
-
130
- const backupDir = getBackupDir()
131
- const timestamp = new Date().toISOString().replace(/[:.]/g, "-")
132
- const backupPath = join(backupDir, `config-${timestamp}.json`)
133
-
134
- await copyFile(configPath, backupPath)
135
- debugLog("Config", `Backup created: ${backupPath}`)
136
- }
137
-
138
- export function createDefaultConfig(rootDir: string): EasiarrConfig {
139
- const now = new Date().toISOString()
140
-
141
- return {
142
- ...DEFAULT_CONFIG,
143
- rootDir,
144
- timezone: detectTimezone(),
145
- uid: detectUid(),
146
- gid: detectGid(),
147
- createdAt: now,
148
- updatedAt: now,
149
- }
150
- }
@@ -1,181 +0,0 @@
1
- /**
2
- * Recyclarr Configuration Generator
3
- * Generates recyclarr.yml for automatic TRaSH Guides profile sync
4
- */
5
-
6
- import { mkdir, writeFile } from "node:fs/promises"
7
- import { join } from "node:path"
8
-
9
- import YAML from "yaml"
10
-
11
- import type { AppId, EasiarrConfig } from "./schema"
12
- import { debugLog } from "~/utils/debug"
13
- import { readEnv } from "~/utils/env"
14
-
15
- /**
16
- * Get API key for an app from the .env file
17
- */
18
- async function getAppApiKey(appId: AppId): Promise<string | null> {
19
- const env = await readEnv()
20
- const envKey = `API_KEY_${appId.toUpperCase()}`
21
- return env[envKey] ?? null
22
- }
23
-
24
- // TRaSH Guide Custom Format IDs for common unwanted content
25
- const UNWANTED_CFS = {
26
- radarr: [
27
- "ed38b889b31be83fda192888e2286d83", // BR-DISK
28
- "90a6f9a284dff5103f6346090e6280c8", // LQ
29
- "e204b80c87be9497a8a6eaff48f72905", // LQ (Release Title)
30
- "dc98083864ea246d05a42df0d05f81cc", // x265 (HD)
31
- "0a3f082873eb454bde444150b70253cc", // Extras
32
- ],
33
- sonarr: [
34
- "85c61753df5da1fb2aab6f2a47426b09", // BR-DISK
35
- "9c11cd3f07101cdba90a2d81cf0e56b4", // LQ
36
- "e2315f990da2e2cbfc9fa5b7a6fcfe48", // LQ (Release Title)
37
- "47435ece6b99a0b477caf360e79ba0bb", // x265 (HD)
38
- "fbcb31d8dabd2a319072b84fc0b7249c", // Extras
39
- ],
40
- }
41
-
42
- // TRaSH Guide Quality Definition types
43
- const QUALITY_DEFINITIONS = {
44
- radarr: "movie",
45
- sonarr: "series",
46
- }
47
-
48
- // Default quality profiles to assign scores to
49
- const DEFAULT_PROFILES = {
50
- radarr: ["HD", "HD-1080p", "Ultra-HD", "Any"],
51
- sonarr: ["WEB-1080p", "WEB-DL (1080p)", "HD-1080p", "Any"],
52
- }
53
-
54
- interface RecyclarrInstance {
55
- base_url: string
56
- api_key: string
57
- quality_definition?: {
58
- type: string
59
- preferred_ratio?: number
60
- }
61
- custom_formats?: Array<{
62
- trash_ids: string[]
63
- quality_profiles: Array<{
64
- name: string
65
- }>
66
- }>
67
- }
68
-
69
- interface RecyclarrConfig {
70
- radarr?: Record<string, RecyclarrInstance>
71
- sonarr?: Record<string, RecyclarrInstance>
72
- }
73
-
74
- /**
75
- * Generate recyclarr.yml configuration for enabled *arr apps
76
- */
77
- export async function generateRecyclarrConfig(config: EasiarrConfig): Promise<string> {
78
- debugLog("Recyclarr", "Generating recyclarr.yml configuration")
79
-
80
- const recyclarrConfig: RecyclarrConfig = {}
81
-
82
- // Check for enabled Radarr
83
- const radarrApp = config.apps.find((a) => a.id === "radarr" && a.enabled)
84
- if (radarrApp) {
85
- const apiKey = await getAppApiKey("radarr")
86
- if (apiKey) {
87
- const port = radarrApp.port ?? 7878
88
- recyclarrConfig.radarr = {
89
- radarr_main: {
90
- base_url: `http://radarr:${port}`,
91
- api_key: apiKey,
92
- quality_definition: {
93
- type: QUALITY_DEFINITIONS.radarr,
94
- preferred_ratio: 0.5,
95
- },
96
- custom_formats: [
97
- {
98
- trash_ids: UNWANTED_CFS.radarr,
99
- quality_profiles: DEFAULT_PROFILES.radarr.map((name) => ({ name })),
100
- },
101
- ],
102
- },
103
- }
104
- debugLog("Recyclarr", "Added Radarr configuration")
105
- } else {
106
- debugLog("Recyclarr", "Radarr enabled but no API key found - skipping")
107
- }
108
- }
109
-
110
- // Check for enabled Sonarr
111
- const sonarrApp = config.apps.find((a) => a.id === "sonarr" && a.enabled)
112
- if (sonarrApp) {
113
- const apiKey = await getAppApiKey("sonarr")
114
- if (apiKey) {
115
- const port = sonarrApp.port ?? 8989
116
- recyclarrConfig.sonarr = {
117
- sonarr_main: {
118
- base_url: `http://sonarr:${port}`,
119
- api_key: apiKey,
120
- quality_definition: {
121
- type: QUALITY_DEFINITIONS.sonarr,
122
- },
123
- custom_formats: [
124
- {
125
- trash_ids: UNWANTED_CFS.sonarr,
126
- quality_profiles: DEFAULT_PROFILES.sonarr.map((name) => ({ name })),
127
- },
128
- ],
129
- },
130
- }
131
- debugLog("Recyclarr", "Added Sonarr configuration")
132
- } else {
133
- debugLog("Recyclarr", "Sonarr enabled but no API key found - skipping")
134
- }
135
- }
136
-
137
- // Generate YAML
138
- const yamlContent = YAML.stringify(recyclarrConfig, {
139
- indent: 2,
140
- lineWidth: 0,
141
- })
142
-
143
- // Add header comment
144
- const header = `# Recyclarr Configuration
145
- # Generated by easiarr - https://github.com/muhammedaksam/easiarr
146
- #
147
- # This configuration syncs TRaSH Guides profiles to your *arr apps.
148
- # Recyclarr runs daily via cron to keep profiles up to date.
149
- #
150
- # For more options, see: https://recyclarr.dev/reference/configuration/
151
- #
152
- # To manually trigger sync: docker compose run --rm recyclarr sync
153
- #
154
-
155
- `
156
-
157
- return header + yamlContent
158
- }
159
-
160
- /**
161
- * Save recyclarr.yml to the config directory
162
- */
163
- export async function saveRecyclarrConfig(config: EasiarrConfig): Promise<string> {
164
- const recyclarrDir = join(config.rootDir, "config", "recyclarr")
165
- await mkdir(recyclarrDir, { recursive: true })
166
-
167
- const configContent = await generateRecyclarrConfig(config)
168
- const configPath = join(recyclarrDir, "recyclarr.yml")
169
-
170
- await writeFile(configPath, configContent, "utf-8")
171
- debugLog("Recyclarr", `Saved recyclarr.yml to ${configPath}`)
172
-
173
- return configPath
174
- }
175
-
176
- /**
177
- * Get the path to the recyclarr config file
178
- */
179
- export function getRecyclarrConfigPath(config: EasiarrConfig): string {
180
- return join(config.rootDir, "config", "recyclarr", "recyclarr.yml")
181
- }
@@ -1,310 +0,0 @@
1
- /**
2
- * easiarr Configuration Schema
3
- * TypeScript interfaces for configuration management
4
- */
5
-
6
- import { VersionInfo } from "~/VersionInfo"
7
-
8
- export interface EasiarrConfig {
9
- version: string
10
- rootDir: string
11
- timezone: string
12
- uid: number
13
- gid: number
14
- umask: string
15
- apps: AppConfig[]
16
- network?: NetworkConfig
17
- /** Which reverse proxy to use: traefik, caddy, or none */
18
- reverseProxy?: "traefik" | "caddy" | "none"
19
- traefik?: TraefikConfig
20
- caddy?: CaddyConfig
21
- vpn?: VpnConfig
22
- monitor?: MonitorConfig
23
- /** Bind-mount container logs to host for external log aggregation */
24
- logMount?: boolean
25
- createdAt: string
26
- updatedAt: string
27
- }
28
-
29
- export type ReverseProxyType = "traefik" | "caddy" | "none"
30
-
31
- export interface CaddyConfig {
32
- enabled: boolean
33
- domain: string
34
- /** Email for ACME/Let's Encrypt */
35
- email?: string
36
- }
37
-
38
- export type VpnMode = "full" | "mini" | "none"
39
-
40
- export interface VpnConfig {
41
- mode: VpnMode
42
- provider?: string // For future use (e.g. custom, airvpn, protonvpn)
43
- }
44
-
45
- // ==========================================
46
- // Monitoring Configuration
47
- // ==========================================
48
-
49
- export type MonitorCheckType = "health" | "diskspace" | "status" | "queue"
50
-
51
- export interface MonitorOptions {
52
- health: boolean
53
- diskspace: boolean
54
- status: boolean
55
- queue: boolean
56
- }
57
-
58
- export interface CategoryMonitorConfig {
59
- category: AppCategory
60
- enabled: boolean
61
- checks: MonitorOptions
62
- }
63
-
64
- export interface AppMonitorConfig {
65
- appId: AppId
66
- override: boolean // If true, uses app-specific settings instead of category defaults
67
- enabled: boolean
68
- checks: MonitorOptions
69
- }
70
-
71
- export interface MonitorConfig {
72
- categories: CategoryMonitorConfig[]
73
- apps: AppMonitorConfig[] // App-specific overrides
74
- pollIntervalSeconds: number
75
- }
76
-
77
- export interface TraefikConfig {
78
- enabled: boolean
79
- domain: string
80
- entrypoint: string
81
- middlewares: string[]
82
- /** Basic auth using username/password */
83
- basicAuth?: {
84
- enabled: boolean
85
- username: string
86
- password: string
87
- }
88
- }
89
-
90
- export interface AppConfig {
91
- id: AppId
92
- enabled: boolean
93
- port?: number
94
- customEnv?: Record<string, string>
95
- customVolumes?: string[]
96
- labels?: string[]
97
- devices?: string[]
98
- cap_add?: string[]
99
- }
100
-
101
- export interface NetworkConfig {
102
- name: string
103
- driver: "bridge" | "host" | "none"
104
- }
105
-
106
- export type AppId =
107
- // Media Management (Servarr)
108
- | "radarr"
109
- | "sonarr"
110
- | "lidarr"
111
- | "readarr"
112
- | "bazarr"
113
- | "mylar3"
114
- | "whisparr"
115
- | "audiobookshelf"
116
- // Indexers
117
- | "prowlarr"
118
- | "jackett"
119
- | "flaresolverr"
120
- // Download Clients
121
- | "qbittorrent"
122
- | "sabnzbd"
123
- | "slskd"
124
- | "soularr"
125
- // Media Servers
126
- | "plex"
127
- | "jellyfin"
128
- | "tautulli"
129
- | "tdarr"
130
- // Request Management
131
- | "overseerr"
132
- | "jellyseerr"
133
- // Dashboards
134
- | "homarr"
135
- | "heimdall"
136
- | "homepage"
137
- // Utilities
138
- | "huntarr"
139
- | "maintainerr"
140
- | "unpackerr"
141
- | "filebot"
142
- | "chromium"
143
- | "guacamole"
144
- | "guacd"
145
- | "ddns-updater"
146
- | "easiarr"
147
- | "recyclarr"
148
- | "profilarr"
149
- // VPN
150
- | "gluetun"
151
- // Monitoring & Infra
152
- | "portainer"
153
- | "dozzle"
154
- | "uptime-kuma"
155
- // Monitoring
156
- | "grafana"
157
- | "prometheus"
158
- // Reverse Proxy
159
- | "traefik"
160
- | "traefik-certs-dumper"
161
- | "caddy"
162
- | "cloudflared"
163
- | "crowdsec"
164
- // Network/VPN
165
- | "headscale"
166
- | "headplane"
167
- | "tailscale"
168
- // Authentication
169
- | "authentik"
170
- | "authentik-worker"
171
- // Database
172
- | "postgresql"
173
- | "valkey"
174
-
175
- export type AppCategory =
176
- | "servarr"
177
- | "indexer"
178
- | "downloader"
179
- | "mediaserver"
180
- | "request"
181
- | "dashboard"
182
- | "utility"
183
- | "vpn"
184
- | "monitoring"
185
- | "infrastructure"
186
-
187
- export type Architecture = "x64" | "arm64" | "arm32"
188
-
189
- export interface ArchCompatibility {
190
- /** Architectures with full support */
191
- supported?: Architecture[]
192
- /** Architectures with deprecated/broken support - will show warning */
193
- deprecated?: Architecture[]
194
- /** Warning message to show for deprecated architectures */
195
- warning?: string
196
- }
197
-
198
- export interface AppDefinition {
199
- id: AppId
200
- name: string
201
- description: string
202
- category: AppCategory
203
- defaultPort: number
204
- /** Internal container port if different from defaultPort */
205
- internalPort?: number
206
- /** Additional port mappings (e.g., "8083:8080" for dashboard ports) */
207
- secondaryPorts?: string[]
208
- image: string
209
- puid: number
210
- pgid: number
211
- volumes: (rootDir: string) => string[]
212
- environment?: Record<string, string>
213
- dependsOn?: AppId[]
214
- trashGuide?: string
215
- secrets?: AppSecret[]
216
- devices?: string[]
217
- cap_add?: string[]
218
- /** Custom command to run (e.g., "tunnel run" for cloudflared) */
219
- command?: string
220
- apiKeyMeta?: ApiKeyMeta
221
- rootFolder?: RootFolderMeta
222
- prowlarrCategoryIds?: number[]
223
- /** Architecture compatibility info - omit if supports all */
224
- arch?: ArchCompatibility
225
- /** Minimum password length requirement for user creation */
226
- minPasswordLength?: number
227
- /** Homepage dashboard configuration */
228
- homepage?: HomepageMeta
229
- /** Auto-setup capability metadata */
230
- autoSetup?: AutoSetupCapability
231
- /** Use Docker's user: directive instead of PUID/PGID env vars (e.g., slskd) */
232
- useDockerUser?: boolean
233
- /** Path inside container where logs are stored (e.g., "/config/logs"), for bind-mounting */
234
- logVolume?: string
235
- }
236
-
237
- /** Auto-setup capability for an app */
238
- export interface AutoSetupCapability {
239
- /** Type of auto-setup support: full (complete config), partial (basic config), manual (user must configure) */
240
- type: "full" | "partial" | "manual"
241
- /** Human-readable description of what gets configured */
242
- description: string
243
- /** Other apps that must be set up first */
244
- requires?: AppId[]
245
- /** Environment variables required for setup */
246
- envVars?: string[]
247
- }
248
-
249
- /** Homepage dashboard widget/service configuration */
250
- export interface HomepageMeta {
251
- /** Icon name from Dashboard Icons (e.g., "radarr.png", "mdi-web") */
252
- icon?: string
253
- /** Widget type for Homepage (e.g., "radarr", "sonarr", "qbittorrent") */
254
- widget?: string
255
- /** Custom widget fields if needed */
256
- widgetFields?: Record<string, string>
257
- }
258
-
259
- export interface RootFolderMeta {
260
- path: string // e.g. "/data/media/movies"
261
- apiVersion: "v1" | "v3"
262
- }
263
-
264
- export interface ApiKeyMeta {
265
- configFile: string // Relative to config volume root
266
- parser: ApiKeyParserType
267
- selector: string // Regex group 1, or XML tag, or INI key, JSON/YAML dot path
268
- /** INI section name (for parser: "ini") */
269
- section?: string
270
- /** INI key that controls if API is enabled (for parser: "ini") */
271
- enabledKey?: string
272
- /** Generate API key if missing or None (for apps like Mylar3) */
273
- generateIfMissing?: boolean
274
- description?: string
275
- transform?: (value: string) => string
276
- }
277
-
278
- export type ApiKeyParserType = "xml" | "ini" | "json" | "yaml" | "regex"
279
-
280
- export interface AppSecret {
281
- name: string
282
- description: string
283
- required: boolean
284
- default?: string
285
- generate?: boolean // Suggest auto-generation
286
- mask?: boolean // Mask input
287
- }
288
-
289
- export const APP_CATEGORIES: Record<AppCategory, string> = {
290
- servarr: "Media Management",
291
- indexer: "Indexers",
292
- downloader: "Download Clients",
293
- mediaserver: "Media Servers",
294
- request: "Request Management",
295
- dashboard: "Dashboards",
296
- utility: "Utilities",
297
- vpn: "VPN",
298
- monitoring: "Monitoring",
299
- infrastructure: "Infrastructure",
300
- }
301
-
302
- export const DEFAULT_CONFIG: Omit<EasiarrConfig, "createdAt" | "updatedAt"> = {
303
- version: VersionInfo.version,
304
- rootDir: "",
305
- timezone: "",
306
- uid: 1000,
307
- gid: 1000,
308
- umask: "002",
309
- apps: [],
310
- }