@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.
- package/dist/index.js +29837 -0
- package/package.json +15 -15
- package/src/VersionInfo.ts +0 -12
- package/src/api/arr-api.ts +0 -521
- package/src/api/auto-setup-types.ts +0 -64
- package/src/api/base-api.ts +0 -216
- package/src/api/bazarr-api.ts +0 -297
- package/src/api/cloudflare-api.ts +0 -493
- package/src/api/custom-format-api.ts +0 -224
- package/src/api/grafana-api.ts +0 -230
- package/src/api/heimdall-api.ts +0 -141
- package/src/api/homarr-api.ts +0 -209
- package/src/api/huntarr-api.ts +0 -457
- package/src/api/index.ts +0 -9
- package/src/api/jellyfin-api.ts +0 -389
- package/src/api/jellyseerr-api.ts +0 -559
- package/src/api/maintainerr-api.ts +0 -461
- package/src/api/naming-config.ts +0 -101
- package/src/api/overseerr-api.ts +0 -392
- package/src/api/plex-api.ts +0 -308
- package/src/api/portainer-api.ts +0 -374
- package/src/api/profilarr-api.ts +0 -391
- package/src/api/prowlarr-api.ts +0 -488
- package/src/api/qbittorrent-api.ts +0 -300
- package/src/api/quality-profile-api.ts +0 -272
- package/src/api/tautulli-api.ts +0 -244
- package/src/api/uptime-kuma-api.ts +0 -343
- package/src/apps/categories.ts +0 -14
- package/src/apps/index.ts +0 -2
- package/src/apps/registry.ts +0 -1275
- package/src/compose/caddy-config.ts +0 -130
- package/src/compose/generator.ts +0 -287
- package/src/compose/index.ts +0 -7
- package/src/compose/templates.ts +0 -78
- package/src/compose/traefik-config.ts +0 -187
- package/src/config/bookmarks-generator.ts +0 -160
- package/src/config/defaults.ts +0 -37
- package/src/config/homepage-config.ts +0 -381
- package/src/config/index.ts +0 -6
- package/src/config/manager.ts +0 -150
- package/src/config/recyclarr-config.ts +0 -181
- package/src/config/schema.ts +0 -310
- package/src/config/slskd-config.ts +0 -86
- package/src/config/soularr-config.ts +0 -105
- package/src/config/trash-quality-definitions.ts +0 -213
- package/src/data/lidarr-custom-formats.ts +0 -127
- package/src/data/trash-profiles.ts +0 -333
- package/src/docker/client.ts +0 -312
- package/src/docker/index.ts +0 -18
- package/src/index.ts +0 -77
- package/src/setup/actions/arr-common.ts +0 -307
- package/src/setup/actions/dashboards.ts +0 -79
- package/src/setup/actions/download-clients.ts +0 -54
- package/src/setup/actions/jellyseerr.ts +0 -331
- package/src/setup/actions/media-servers.ts +0 -68
- package/src/setup/actions/monitoring.ts +0 -120
- package/src/setup/actions/prowlarr.ts +0 -137
- package/src/setup/actions/utilities.ts +0 -490
- package/src/setup/index.ts +0 -78
- package/src/setup/types.ts +0 -144
- package/src/structure/manager.ts +0 -129
- package/src/ui/App.ts +0 -111
- package/src/ui/components/ApplicationSelector.ts +0 -275
- package/src/ui/components/CredentialsForm.ts +0 -180
- package/src/ui/components/DownloadClientForm.ts +0 -114
- package/src/ui/components/FileEditor.ts +0 -91
- package/src/ui/components/FooterHint.ts +0 -119
- package/src/ui/components/PageLayout.ts +0 -160
- package/src/ui/components/UpdateNotification.ts +0 -102
- package/src/ui/index.ts +0 -7
- package/src/ui/screens/AdvancedSettings.ts +0 -188
- package/src/ui/screens/ApiKeyViewer.ts +0 -511
- package/src/ui/screens/AppConfigurator.ts +0 -543
- package/src/ui/screens/AppManager.ts +0 -284
- package/src/ui/screens/ContainerControl.ts +0 -581
- package/src/ui/screens/LogsViewer.ts +0 -478
- package/src/ui/screens/MainMenu.ts +0 -299
- package/src/ui/screens/MonitorDashboard.ts +0 -881
- package/src/ui/screens/SecretsEditor.ts +0 -216
- package/src/ui/screens/SettingsScreen.ts +0 -633
- package/src/ui/screens/index.ts +0 -22
- package/src/ui/screens/setup/BaseAppSetupScreen.ts +0 -375
- package/src/ui/screens/setup/CloudflaredSetup.ts +0 -460
- package/src/ui/screens/setup/FullAutoSetup.ts +0 -766
- package/src/ui/screens/setup/HomepageSetup.ts +0 -165
- package/src/ui/screens/setup/JellyfinSetup.ts +0 -328
- package/src/ui/screens/setup/JellyseerrSetup.ts +0 -242
- package/src/ui/screens/setup/ProwlarrSetup.ts +0 -500
- package/src/ui/screens/setup/QBittorrentSetup.ts +0 -221
- package/src/ui/screens/setup/QuickSetup.ts +0 -1169
- package/src/ui/screens/setup/RecyclarrSetup.ts +0 -270
- package/src/ui/screens/setup/TRaSHProfileSetup.ts +0 -381
- package/src/utils/arch.ts +0 -78
- package/src/utils/browser.ts +0 -27
- package/src/utils/categories.ts +0 -61
- package/src/utils/debug.ts +0 -84
- package/src/utils/env.ts +0 -138
- package/src/utils/index.ts +0 -8
- package/src/utils/logs.ts +0 -119
- package/src/utils/migrations/1765626338_rename_env_variables.ts +0 -102
- package/src/utils/migrations/1765707135_rename_easiarr_status.ts +0 -91
- package/src/utils/migrations/1765732722_remove_cloudflare_dns_api_token.ts +0 -45
- package/src/utils/migrations/1769515650_migrate_to_xdg.ts +0 -114
- package/src/utils/migrations.ts +0 -165
- package/src/utils/password.ts +0 -42
- package/src/utils/paths.ts +0 -33
- package/src/utils/unraid.ts +0 -103
- package/src/utils/update-checker.ts +0 -210
- package/src/utils/url-utils.ts +0 -38
package/src/config/manager.ts
DELETED
|
@@ -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
|
-
}
|
package/src/config/schema.ts
DELETED
|
@@ -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
|
-
}
|