@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
|
@@ -1,766 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Full Auto Setup Screen
|
|
3
|
-
* Runs all configuration steps in sequence
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { BoxRenderable, CliRenderer, KeyEvent, TextRenderable } from "@opentui/core"
|
|
7
|
-
|
|
8
|
-
import type { EasiarrConfig } from "~/config/schema"
|
|
9
|
-
import { saveCompose } from "~/compose"
|
|
10
|
-
import { saveConfig } from "~/config"
|
|
11
|
-
import {
|
|
12
|
-
createSetupContext,
|
|
13
|
-
runJellyseerrFullSetup,
|
|
14
|
-
setupArrAuthentication,
|
|
15
|
-
setupArrExternalUrls,
|
|
16
|
-
setupArrNaming,
|
|
17
|
-
setupArrQuality,
|
|
18
|
-
setupArrRootFolders,
|
|
19
|
-
setupBazarr as setupBazarrAction,
|
|
20
|
-
setupBazarrAuthentication,
|
|
21
|
-
setupCloudflare as setupCloudflareAction,
|
|
22
|
-
setupFlareSolverr,
|
|
23
|
-
setupGrafana as setupGrafanaAction,
|
|
24
|
-
setupHeimdall as setupHeimdallAction,
|
|
25
|
-
setupHomarr as setupHomarrAction,
|
|
26
|
-
setupHuntarr as setupHuntarrAction,
|
|
27
|
-
setupJellyfin as setupJellyfinAction,
|
|
28
|
-
setupMaintainerr as setupMaintainerrAction,
|
|
29
|
-
setupOverseerr as setupOverseerrAction,
|
|
30
|
-
setupPlex as setupPlexAction,
|
|
31
|
-
setupPortainer as setupPortainerAction,
|
|
32
|
-
setupProfilarr as setupProfilarrAction,
|
|
33
|
-
setupProwlarrApps,
|
|
34
|
-
setupQBittorrent as setupQBittorrentAction,
|
|
35
|
-
setupRecyclarr as setupRecyclarrAction,
|
|
36
|
-
setupSlskd as setupSlskdAction,
|
|
37
|
-
setupSoularr as setupSoularrAction,
|
|
38
|
-
setupTautulli as setupTautulliAction,
|
|
39
|
-
setupUptimeKuma as setupUptimeKumaAction,
|
|
40
|
-
} from "~/setup"
|
|
41
|
-
import { createPageLayout } from "~/ui/components/PageLayout"
|
|
42
|
-
import { debugLog } from "~/utils/debug"
|
|
43
|
-
import { readEnvSync, updateEnv } from "~/utils/env"
|
|
44
|
-
|
|
45
|
-
interface SetupStep {
|
|
46
|
-
name: string
|
|
47
|
-
status: "pending" | "running" | "success" | "error" | "skipped"
|
|
48
|
-
message?: string
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export class FullAutoSetup extends BoxRenderable {
|
|
52
|
-
private config: EasiarrConfig
|
|
53
|
-
private cliRenderer: CliRenderer
|
|
54
|
-
private onBack: () => void
|
|
55
|
-
private keyHandler!: (key: KeyEvent) => void
|
|
56
|
-
private contentBox!: BoxRenderable
|
|
57
|
-
private pageContainer!: BoxRenderable
|
|
58
|
-
|
|
59
|
-
private isRunning = false
|
|
60
|
-
private isDone = false
|
|
61
|
-
private steps: SetupStep[] = []
|
|
62
|
-
private globalUsername = ""
|
|
63
|
-
private globalPassword = ""
|
|
64
|
-
private env: Record<string, string> = {}
|
|
65
|
-
|
|
66
|
-
constructor(cliRenderer: CliRenderer, config: EasiarrConfig, onBack: () => void) {
|
|
67
|
-
const { container: pageContainer, content: contentBox } = createPageLayout(cliRenderer, {
|
|
68
|
-
title: "Full Auto Setup",
|
|
69
|
-
stepInfo: "Configure all services automatically",
|
|
70
|
-
footerHint: [
|
|
71
|
-
{ type: "key", key: "Enter", value: "Start/Continue" },
|
|
72
|
-
{ type: "key", key: "Esc", value: "Back" },
|
|
73
|
-
],
|
|
74
|
-
})
|
|
75
|
-
super(cliRenderer, { width: "100%", height: "100%" })
|
|
76
|
-
this.add(pageContainer)
|
|
77
|
-
|
|
78
|
-
this.config = config
|
|
79
|
-
this.cliRenderer = cliRenderer
|
|
80
|
-
this.onBack = onBack
|
|
81
|
-
this.contentBox = contentBox
|
|
82
|
-
this.pageContainer = pageContainer
|
|
83
|
-
|
|
84
|
-
this.env = readEnvSync()
|
|
85
|
-
this.globalUsername = this.env["USERNAME_GLOBAL"] || "admin"
|
|
86
|
-
this.globalPassword = this.env["PASSWORD_GLOBAL"] || "Ch4ng3m3!1234securityReasons"
|
|
87
|
-
|
|
88
|
-
this.initKeyHandler()
|
|
89
|
-
this.initSteps()
|
|
90
|
-
this.refreshContent()
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
private initSteps(): void {
|
|
94
|
-
this.steps = [
|
|
95
|
-
{ name: "Root Folders", status: "pending" },
|
|
96
|
-
{ name: "Naming Scheme", status: "pending" },
|
|
97
|
-
{ name: "Quality Settings", status: "pending" },
|
|
98
|
-
{ name: "Authentication", status: "pending" },
|
|
99
|
-
{ name: "External URLs", status: "pending" },
|
|
100
|
-
{ name: "Prowlarr Apps", status: "pending" },
|
|
101
|
-
{ name: "FlareSolverr", status: "pending" },
|
|
102
|
-
{ name: "qBittorrent", status: "pending" },
|
|
103
|
-
{ name: "Portainer", status: "pending" },
|
|
104
|
-
{ name: "Jellyfin", status: "pending" },
|
|
105
|
-
{ name: "Jellyseerr", status: "pending" },
|
|
106
|
-
{ name: "Plex", status: "pending" },
|
|
107
|
-
{ name: "Overseerr", status: "pending" },
|
|
108
|
-
{ name: "Tautulli", status: "pending" },
|
|
109
|
-
{ name: "Maintainerr", status: "pending" },
|
|
110
|
-
{ name: "Bazarr", status: "pending" },
|
|
111
|
-
{ name: "Uptime Kuma", status: "pending" },
|
|
112
|
-
{ name: "Grafana", status: "pending" },
|
|
113
|
-
{ name: "Homarr", status: "pending" },
|
|
114
|
-
{ name: "Heimdall", status: "pending" },
|
|
115
|
-
{ name: "Huntarr", status: "pending" },
|
|
116
|
-
{ name: "Slskd", status: "pending" },
|
|
117
|
-
{ name: "Soularr", status: "pending" },
|
|
118
|
-
{ name: "Recyclarr", status: "pending" },
|
|
119
|
-
{ name: "Profilarr", status: "pending" },
|
|
120
|
-
{ name: "Cloudflare Tunnel", status: "pending" },
|
|
121
|
-
]
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
private initKeyHandler(): void {
|
|
125
|
-
this.keyHandler = (key: KeyEvent) => {
|
|
126
|
-
debugLog("FullAutoSetup", `Key: ${key.name}, running=${this.isRunning}`)
|
|
127
|
-
|
|
128
|
-
if (key.name === "escape" || (key.name === "c" && key.ctrl)) {
|
|
129
|
-
if (!this.isRunning) {
|
|
130
|
-
this.cleanup()
|
|
131
|
-
}
|
|
132
|
-
return
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
if (key.name === "return") {
|
|
136
|
-
if (this.isDone) {
|
|
137
|
-
this.cleanup()
|
|
138
|
-
} else if (!this.isRunning) {
|
|
139
|
-
this.runSetup()
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
this.cliRenderer.keyInput.on("keypress", this.keyHandler)
|
|
144
|
-
debugLog("FullAutoSetup", "Key handler registered")
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
private async runSetup(): Promise<void> {
|
|
148
|
-
this.isRunning = true
|
|
149
|
-
this.refreshContent()
|
|
150
|
-
|
|
151
|
-
// Step 1: Root folders
|
|
152
|
-
await this.setupRootFolders()
|
|
153
|
-
|
|
154
|
-
// Step 2: Naming Scheme
|
|
155
|
-
await this.setupNaming()
|
|
156
|
-
|
|
157
|
-
// Step 2b: Quality Settings
|
|
158
|
-
await this.setupQuality()
|
|
159
|
-
|
|
160
|
-
// Step 3: Authentication
|
|
161
|
-
await this.setupAuthentication()
|
|
162
|
-
|
|
163
|
-
// Step 3: External URLs
|
|
164
|
-
await this.setupExternalUrls()
|
|
165
|
-
|
|
166
|
-
// Step 4: Prowlarr apps
|
|
167
|
-
await this.setupProwlarrApps()
|
|
168
|
-
|
|
169
|
-
// Step 5: FlareSolverr
|
|
170
|
-
await this.setupFlareSolverr()
|
|
171
|
-
|
|
172
|
-
// Step 6: qBittorrent
|
|
173
|
-
await this.setupQBittorrent()
|
|
174
|
-
|
|
175
|
-
// Step 7: Portainer
|
|
176
|
-
await this.setupPortainer()
|
|
177
|
-
|
|
178
|
-
// Step 8: Jellyfin
|
|
179
|
-
await this.setupJellyfin()
|
|
180
|
-
|
|
181
|
-
// Step 9: Jellyseerr
|
|
182
|
-
await this.setupJellyseerr()
|
|
183
|
-
|
|
184
|
-
// Step 10: Plex
|
|
185
|
-
await this.setupPlex()
|
|
186
|
-
|
|
187
|
-
// Step 11: Overseerr (requires Plex)
|
|
188
|
-
await this.setupOverseerr()
|
|
189
|
-
|
|
190
|
-
// Step 12: Tautulli (Plex monitoring)
|
|
191
|
-
await this.setupTautulli()
|
|
192
|
-
|
|
193
|
-
// Step 12b: Maintainerr (Plex media management)
|
|
194
|
-
await this.setupMaintainerr()
|
|
195
|
-
|
|
196
|
-
// Step 13: Bazarr (subtitles)
|
|
197
|
-
await this.setupBazarr()
|
|
198
|
-
|
|
199
|
-
// Step 14: Uptime Kuma (monitors)
|
|
200
|
-
await this.setupUptimeKuma()
|
|
201
|
-
|
|
202
|
-
// Step 15: Grafana (dashboards)
|
|
203
|
-
await this.setupGrafana()
|
|
204
|
-
|
|
205
|
-
// Step 16: Homarr (dashboard)
|
|
206
|
-
await this.setupHomarr()
|
|
207
|
-
|
|
208
|
-
// Step 17: Heimdall (dashboard)
|
|
209
|
-
await this.setupHeimdall()
|
|
210
|
-
|
|
211
|
-
// Step 18: Huntarr (*arr app manager)
|
|
212
|
-
await this.setupHuntarr()
|
|
213
|
-
|
|
214
|
-
// Step 19: Slskd (Soulseek client)
|
|
215
|
-
await this.setupSlskd()
|
|
216
|
-
|
|
217
|
-
// Step 20: Soularr (Lidarr -> Slskd bridge)
|
|
218
|
-
await this.setupSoularr()
|
|
219
|
-
|
|
220
|
-
// Step 21: Recyclarr (TRaSH Guides sync)
|
|
221
|
-
await this.setupRecyclarr()
|
|
222
|
-
|
|
223
|
-
// Step 22: Profilarr (Alternative TRaSH Guides sync)
|
|
224
|
-
await this.setupProfilarr()
|
|
225
|
-
|
|
226
|
-
// Step 22: Cloudflare Tunnel
|
|
227
|
-
await this.setupCloudflare()
|
|
228
|
-
|
|
229
|
-
this.isRunning = false
|
|
230
|
-
this.isDone = true
|
|
231
|
-
this.refreshContent()
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
private async setupRootFolders(): Promise<void> {
|
|
235
|
-
this.updateStep("Root Folders", "running")
|
|
236
|
-
this.refreshContent()
|
|
237
|
-
|
|
238
|
-
const ctx = createSetupContext(this.config, this.env)
|
|
239
|
-
const result = await setupArrRootFolders(ctx)
|
|
240
|
-
|
|
241
|
-
this.updateStep("Root Folders", result.success ? "success" : "error", result.message)
|
|
242
|
-
this.refreshContent()
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
private async setupNaming(): Promise<void> {
|
|
246
|
-
this.updateStep("Naming Scheme", "running")
|
|
247
|
-
this.refreshContent()
|
|
248
|
-
|
|
249
|
-
const ctx = createSetupContext(this.config, this.env)
|
|
250
|
-
const result = await setupArrNaming(ctx)
|
|
251
|
-
|
|
252
|
-
this.updateStep("Naming Scheme", result.success ? "success" : "error", result.message)
|
|
253
|
-
this.refreshContent()
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
private async setupQuality(): Promise<void> {
|
|
257
|
-
this.updateStep("Quality Settings", "running")
|
|
258
|
-
this.refreshContent()
|
|
259
|
-
|
|
260
|
-
const ctx = createSetupContext(this.config, this.env)
|
|
261
|
-
const result = await setupArrQuality(ctx)
|
|
262
|
-
|
|
263
|
-
this.updateStep("Quality Settings", result.success ? "success" : "error", result.message)
|
|
264
|
-
this.refreshContent()
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
private async setupAuthentication(): Promise<void> {
|
|
268
|
-
this.updateStep("Authentication", "running")
|
|
269
|
-
this.refreshContent()
|
|
270
|
-
|
|
271
|
-
const ctx = createSetupContext(this.config, this.env)
|
|
272
|
-
|
|
273
|
-
// Setup *arr apps authentication
|
|
274
|
-
const arrResult = await setupArrAuthentication(ctx)
|
|
275
|
-
|
|
276
|
-
// Setup Bazarr authentication and connections
|
|
277
|
-
const bazarrResult = await setupBazarrAuthentication(ctx)
|
|
278
|
-
|
|
279
|
-
// Determine overall status
|
|
280
|
-
const success = arrResult.success || bazarrResult.success
|
|
281
|
-
const skipped = !arrResult.success && arrResult.message === "No PASSWORD_GLOBAL set"
|
|
282
|
-
|
|
283
|
-
if (skipped) {
|
|
284
|
-
this.updateStep("Authentication", "skipped", "No PASSWORD_GLOBAL set")
|
|
285
|
-
} else {
|
|
286
|
-
this.updateStep("Authentication", success ? "success" : "error", arrResult.message)
|
|
287
|
-
}
|
|
288
|
-
this.refreshContent()
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
private async setupExternalUrls(): Promise<void> {
|
|
292
|
-
this.updateStep("External URLs", "running")
|
|
293
|
-
this.refreshContent()
|
|
294
|
-
|
|
295
|
-
const ctx = createSetupContext(this.config, this.env)
|
|
296
|
-
const result = await setupArrExternalUrls(ctx)
|
|
297
|
-
|
|
298
|
-
if (result.success) {
|
|
299
|
-
this.updateStep("External URLs", "success", result.message)
|
|
300
|
-
} else {
|
|
301
|
-
this.updateStep("External URLs", "skipped", result.message)
|
|
302
|
-
}
|
|
303
|
-
this.refreshContent()
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
private async setupProwlarrApps(): Promise<void> {
|
|
307
|
-
this.updateStep("Prowlarr Apps", "running")
|
|
308
|
-
this.refreshContent()
|
|
309
|
-
|
|
310
|
-
const ctx = createSetupContext(this.config, this.env)
|
|
311
|
-
const result = await setupProwlarrApps(ctx)
|
|
312
|
-
|
|
313
|
-
if (result.success) {
|
|
314
|
-
this.updateStep("Prowlarr Apps", "success", result.message)
|
|
315
|
-
} else {
|
|
316
|
-
this.updateStep("Prowlarr Apps", "skipped", result.message)
|
|
317
|
-
}
|
|
318
|
-
this.refreshContent()
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
private async setupFlareSolverr(): Promise<void> {
|
|
322
|
-
this.updateStep("FlareSolverr", "running")
|
|
323
|
-
this.refreshContent()
|
|
324
|
-
|
|
325
|
-
const ctx = createSetupContext(this.config, this.env)
|
|
326
|
-
const result = await setupFlareSolverr(ctx)
|
|
327
|
-
|
|
328
|
-
if (result.success) {
|
|
329
|
-
this.updateStep("FlareSolverr", "success", result.message)
|
|
330
|
-
} else {
|
|
331
|
-
this.updateStep("FlareSolverr", "skipped", result.message)
|
|
332
|
-
}
|
|
333
|
-
this.refreshContent()
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
private async setupQBittorrent(): Promise<void> {
|
|
337
|
-
this.updateStep("qBittorrent", "running")
|
|
338
|
-
this.refreshContent()
|
|
339
|
-
|
|
340
|
-
const ctx = createSetupContext(this.config, this.env)
|
|
341
|
-
const result = await setupQBittorrentAction(ctx)
|
|
342
|
-
|
|
343
|
-
if (result.success) {
|
|
344
|
-
this.updateStep("qBittorrent", "success", result.message)
|
|
345
|
-
} else {
|
|
346
|
-
this.updateStep("qBittorrent", "skipped", result.message)
|
|
347
|
-
}
|
|
348
|
-
this.refreshContent()
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
private async setupPortainer(): Promise<void> {
|
|
352
|
-
this.updateStep("Portainer", "running")
|
|
353
|
-
this.refreshContent()
|
|
354
|
-
|
|
355
|
-
const ctx = createSetupContext(this.config, this.env)
|
|
356
|
-
const result = await setupPortainerAction(ctx)
|
|
357
|
-
|
|
358
|
-
if (result.success) {
|
|
359
|
-
if (result.envUpdates) {
|
|
360
|
-
await updateEnv(result.envUpdates)
|
|
361
|
-
Object.assign(this.env, result.envUpdates)
|
|
362
|
-
}
|
|
363
|
-
this.updateStep("Portainer", "success", result.message)
|
|
364
|
-
} else {
|
|
365
|
-
this.updateStep("Portainer", "skipped", result.message)
|
|
366
|
-
}
|
|
367
|
-
this.refreshContent()
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
private async setupJellyfin(): Promise<void> {
|
|
371
|
-
this.updateStep("Jellyfin", "running")
|
|
372
|
-
this.refreshContent()
|
|
373
|
-
|
|
374
|
-
const ctx = createSetupContext(this.config, this.env)
|
|
375
|
-
const result = await setupJellyfinAction(ctx)
|
|
376
|
-
|
|
377
|
-
if (result.success) {
|
|
378
|
-
if (result.envUpdates) {
|
|
379
|
-
await updateEnv(result.envUpdates)
|
|
380
|
-
Object.assign(this.env, result.envUpdates)
|
|
381
|
-
}
|
|
382
|
-
this.updateStep("Jellyfin", "success", result.message)
|
|
383
|
-
} else {
|
|
384
|
-
this.updateStep("Jellyfin", "skipped", result.message)
|
|
385
|
-
}
|
|
386
|
-
this.refreshContent()
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
private async setupJellyseerr(): Promise<void> {
|
|
390
|
-
this.updateStep("Jellyseerr", "running")
|
|
391
|
-
this.refreshContent()
|
|
392
|
-
|
|
393
|
-
const ctx = createSetupContext(this.config, this.env)
|
|
394
|
-
const result = await runJellyseerrFullSetup(ctx)
|
|
395
|
-
|
|
396
|
-
if (result.success) {
|
|
397
|
-
if (result.envUpdates) {
|
|
398
|
-
await updateEnv(result.envUpdates)
|
|
399
|
-
Object.assign(this.env, result.envUpdates)
|
|
400
|
-
}
|
|
401
|
-
this.updateStep("Jellyseerr", "success", result.message)
|
|
402
|
-
} else {
|
|
403
|
-
this.updateStep("Jellyseerr", "skipped", result.message)
|
|
404
|
-
}
|
|
405
|
-
this.refreshContent()
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
private async setupPlex(): Promise<void> {
|
|
409
|
-
this.updateStep("Plex", "running")
|
|
410
|
-
this.refreshContent()
|
|
411
|
-
|
|
412
|
-
const ctx = createSetupContext(this.config, this.env)
|
|
413
|
-
const result = await setupPlexAction(ctx)
|
|
414
|
-
|
|
415
|
-
if (result.success) {
|
|
416
|
-
this.updateStep("Plex", "success", result.message)
|
|
417
|
-
} else {
|
|
418
|
-
this.updateStep("Plex", "skipped", result.message)
|
|
419
|
-
}
|
|
420
|
-
this.refreshContent()
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
private async setupUptimeKuma(): Promise<void> {
|
|
424
|
-
this.updateStep("Uptime Kuma", "running")
|
|
425
|
-
this.refreshContent()
|
|
426
|
-
|
|
427
|
-
const ctx = createSetupContext(this.config, this.env)
|
|
428
|
-
const result = await setupUptimeKumaAction(ctx)
|
|
429
|
-
|
|
430
|
-
if (result.success) {
|
|
431
|
-
this.updateStep("Uptime Kuma", "success", result.message)
|
|
432
|
-
} else {
|
|
433
|
-
this.updateStep("Uptime Kuma", "skipped", result.message)
|
|
434
|
-
}
|
|
435
|
-
this.refreshContent()
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
private async setupGrafana(): Promise<void> {
|
|
439
|
-
this.updateStep("Grafana", "running")
|
|
440
|
-
this.refreshContent()
|
|
441
|
-
|
|
442
|
-
const ctx = createSetupContext(this.config, this.env)
|
|
443
|
-
const result = await setupGrafanaAction(ctx)
|
|
444
|
-
|
|
445
|
-
if (result.success) {
|
|
446
|
-
if (result.envUpdates) {
|
|
447
|
-
await updateEnv(result.envUpdates)
|
|
448
|
-
Object.assign(this.env, result.envUpdates)
|
|
449
|
-
}
|
|
450
|
-
this.updateStep("Grafana", "success", result.message)
|
|
451
|
-
} else {
|
|
452
|
-
this.updateStep("Grafana", "skipped", result.message)
|
|
453
|
-
}
|
|
454
|
-
this.refreshContent()
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
private async setupCloudflare(): Promise<void> {
|
|
458
|
-
this.updateStep("Cloudflare Tunnel", "running")
|
|
459
|
-
this.refreshContent()
|
|
460
|
-
|
|
461
|
-
const ctx = createSetupContext(this.config, this.env)
|
|
462
|
-
const result = await setupCloudflareAction(ctx)
|
|
463
|
-
|
|
464
|
-
if (result.success) {
|
|
465
|
-
if (result.envUpdates) {
|
|
466
|
-
await updateEnv(result.envUpdates)
|
|
467
|
-
Object.assign(this.env, result.envUpdates)
|
|
468
|
-
}
|
|
469
|
-
// Update config if tunnel was created
|
|
470
|
-
if (this.config.traefik && result.envUpdates?.CLOUDFLARE_DNS_ZONE) {
|
|
471
|
-
this.config.traefik.domain = result.envUpdates.CLOUDFLARE_DNS_ZONE
|
|
472
|
-
this.config.traefik.entrypoint = "web"
|
|
473
|
-
this.config.updatedAt = new Date().toISOString()
|
|
474
|
-
await saveConfig(this.config)
|
|
475
|
-
await saveCompose(this.config)
|
|
476
|
-
}
|
|
477
|
-
this.updateStep("Cloudflare Tunnel", "success", result.message)
|
|
478
|
-
} else {
|
|
479
|
-
this.updateStep("Cloudflare Tunnel", "skipped", result.message)
|
|
480
|
-
}
|
|
481
|
-
this.refreshContent()
|
|
482
|
-
}
|
|
483
|
-
|
|
484
|
-
private async setupOverseerr(): Promise<void> {
|
|
485
|
-
this.updateStep("Overseerr", "running")
|
|
486
|
-
this.refreshContent()
|
|
487
|
-
|
|
488
|
-
const ctx = createSetupContext(this.config, this.env)
|
|
489
|
-
const result = await setupOverseerrAction(ctx)
|
|
490
|
-
|
|
491
|
-
if (result.success) {
|
|
492
|
-
if (result.envUpdates) {
|
|
493
|
-
await updateEnv(result.envUpdates)
|
|
494
|
-
Object.assign(this.env, result.envUpdates)
|
|
495
|
-
}
|
|
496
|
-
this.updateStep("Overseerr", "success", result.message)
|
|
497
|
-
} else {
|
|
498
|
-
this.updateStep("Overseerr", "skipped", result.message)
|
|
499
|
-
}
|
|
500
|
-
this.refreshContent()
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
private async setupTautulli(): Promise<void> {
|
|
504
|
-
this.updateStep("Tautulli", "running")
|
|
505
|
-
this.refreshContent()
|
|
506
|
-
|
|
507
|
-
const ctx = createSetupContext(this.config, this.env)
|
|
508
|
-
const result = await setupTautulliAction(ctx)
|
|
509
|
-
|
|
510
|
-
if (result.success) {
|
|
511
|
-
if (result.envUpdates) {
|
|
512
|
-
await updateEnv(result.envUpdates)
|
|
513
|
-
Object.assign(this.env, result.envUpdates)
|
|
514
|
-
}
|
|
515
|
-
this.updateStep("Tautulli", "success", result.message)
|
|
516
|
-
} else {
|
|
517
|
-
this.updateStep("Tautulli", "skipped", result.message)
|
|
518
|
-
}
|
|
519
|
-
this.refreshContent()
|
|
520
|
-
}
|
|
521
|
-
|
|
522
|
-
private async setupMaintainerr(): Promise<void> {
|
|
523
|
-
this.updateStep("Maintainerr", "running")
|
|
524
|
-
this.refreshContent()
|
|
525
|
-
|
|
526
|
-
const ctx = createSetupContext(this.config, this.env)
|
|
527
|
-
const result = await setupMaintainerrAction(ctx)
|
|
528
|
-
|
|
529
|
-
if (result.success) {
|
|
530
|
-
if (result.envUpdates) {
|
|
531
|
-
await updateEnv(result.envUpdates)
|
|
532
|
-
Object.assign(this.env, result.envUpdates)
|
|
533
|
-
}
|
|
534
|
-
this.updateStep("Maintainerr", "success", result.message)
|
|
535
|
-
} else {
|
|
536
|
-
this.updateStep("Maintainerr", "skipped", result.message)
|
|
537
|
-
}
|
|
538
|
-
this.refreshContent()
|
|
539
|
-
}
|
|
540
|
-
|
|
541
|
-
private async setupBazarr(): Promise<void> {
|
|
542
|
-
this.updateStep("Bazarr", "running")
|
|
543
|
-
this.refreshContent()
|
|
544
|
-
|
|
545
|
-
const ctx = createSetupContext(this.config, this.env)
|
|
546
|
-
const result = await setupBazarrAction(ctx)
|
|
547
|
-
|
|
548
|
-
if (result.success) {
|
|
549
|
-
if (result.envUpdates) {
|
|
550
|
-
await updateEnv(result.envUpdates)
|
|
551
|
-
Object.assign(this.env, result.envUpdates)
|
|
552
|
-
}
|
|
553
|
-
this.updateStep("Bazarr", "success", result.message)
|
|
554
|
-
} else {
|
|
555
|
-
this.updateStep("Bazarr", "skipped", result.message)
|
|
556
|
-
}
|
|
557
|
-
this.refreshContent()
|
|
558
|
-
}
|
|
559
|
-
|
|
560
|
-
private async setupHomarr(): Promise<void> {
|
|
561
|
-
this.updateStep("Homarr", "running")
|
|
562
|
-
this.refreshContent()
|
|
563
|
-
|
|
564
|
-
const ctx = createSetupContext(this.config, this.env)
|
|
565
|
-
const result = await setupHomarrAction(ctx)
|
|
566
|
-
|
|
567
|
-
if (result.success) {
|
|
568
|
-
this.updateStep("Homarr", "success", result.message)
|
|
569
|
-
} else {
|
|
570
|
-
this.updateStep("Homarr", "skipped", result.message)
|
|
571
|
-
}
|
|
572
|
-
this.refreshContent()
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
private async setupHuntarr(): Promise<void> {
|
|
576
|
-
this.updateStep("Huntarr", "running")
|
|
577
|
-
this.refreshContent()
|
|
578
|
-
|
|
579
|
-
const ctx = createSetupContext(this.config, this.env)
|
|
580
|
-
const result = await setupHuntarrAction(ctx)
|
|
581
|
-
|
|
582
|
-
if (result.success) {
|
|
583
|
-
this.updateStep("Huntarr", "success", result.message)
|
|
584
|
-
} else {
|
|
585
|
-
this.updateStep("Huntarr", "skipped", result.message)
|
|
586
|
-
}
|
|
587
|
-
this.refreshContent()
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
private async setupHeimdall(): Promise<void> {
|
|
591
|
-
this.updateStep("Heimdall", "running")
|
|
592
|
-
this.refreshContent()
|
|
593
|
-
|
|
594
|
-
const ctx = createSetupContext(this.config, this.env)
|
|
595
|
-
const result = await setupHeimdallAction(ctx)
|
|
596
|
-
|
|
597
|
-
if (result.success) {
|
|
598
|
-
this.updateStep("Heimdall", "success", result.message)
|
|
599
|
-
} else {
|
|
600
|
-
this.updateStep("Heimdall", "skipped", result.message)
|
|
601
|
-
}
|
|
602
|
-
this.refreshContent()
|
|
603
|
-
}
|
|
604
|
-
|
|
605
|
-
private async setupSlskd(): Promise<void> {
|
|
606
|
-
this.updateStep("Slskd", "running")
|
|
607
|
-
this.refreshContent()
|
|
608
|
-
|
|
609
|
-
const ctx = createSetupContext(this.config, this.env)
|
|
610
|
-
const result = await setupSlskdAction(ctx)
|
|
611
|
-
|
|
612
|
-
if (result.success) {
|
|
613
|
-
if (result.envUpdates) {
|
|
614
|
-
await updateEnv(result.envUpdates)
|
|
615
|
-
Object.assign(this.env, result.envUpdates)
|
|
616
|
-
}
|
|
617
|
-
this.updateStep("Slskd", "success", result.message)
|
|
618
|
-
} else {
|
|
619
|
-
this.updateStep("Slskd", "skipped", result.message)
|
|
620
|
-
}
|
|
621
|
-
this.refreshContent()
|
|
622
|
-
}
|
|
623
|
-
|
|
624
|
-
private async setupSoularr(): Promise<void> {
|
|
625
|
-
this.updateStep("Soularr", "running")
|
|
626
|
-
this.refreshContent()
|
|
627
|
-
|
|
628
|
-
const ctx = createSetupContext(this.config, this.env)
|
|
629
|
-
const result = await setupSoularrAction(ctx)
|
|
630
|
-
|
|
631
|
-
if (result.success) {
|
|
632
|
-
this.updateStep("Soularr", "success", result.message)
|
|
633
|
-
} else {
|
|
634
|
-
this.updateStep("Soularr", "skipped", result.message)
|
|
635
|
-
}
|
|
636
|
-
this.refreshContent()
|
|
637
|
-
}
|
|
638
|
-
|
|
639
|
-
private async setupRecyclarr(): Promise<void> {
|
|
640
|
-
this.updateStep("Recyclarr", "running")
|
|
641
|
-
this.refreshContent()
|
|
642
|
-
|
|
643
|
-
const ctx = createSetupContext(this.config, this.env)
|
|
644
|
-
const result = await setupRecyclarrAction(ctx)
|
|
645
|
-
|
|
646
|
-
if (result.success) {
|
|
647
|
-
this.updateStep("Recyclarr", "success", result.message)
|
|
648
|
-
} else {
|
|
649
|
-
this.updateStep("Recyclarr", "skipped", result.message)
|
|
650
|
-
}
|
|
651
|
-
this.refreshContent()
|
|
652
|
-
}
|
|
653
|
-
|
|
654
|
-
private async setupProfilarr(): Promise<void> {
|
|
655
|
-
this.updateStep("Profilarr", "running")
|
|
656
|
-
this.refreshContent()
|
|
657
|
-
|
|
658
|
-
const ctx = createSetupContext(this.config, this.env)
|
|
659
|
-
const result = await setupProfilarrAction(ctx)
|
|
660
|
-
|
|
661
|
-
if (result.success) {
|
|
662
|
-
if (result.envUpdates) {
|
|
663
|
-
await updateEnv(result.envUpdates)
|
|
664
|
-
Object.assign(this.env, result.envUpdates)
|
|
665
|
-
}
|
|
666
|
-
this.updateStep("Profilarr", "success", result.message)
|
|
667
|
-
} else {
|
|
668
|
-
this.updateStep("Profilarr", "skipped", result.message)
|
|
669
|
-
}
|
|
670
|
-
this.refreshContent()
|
|
671
|
-
}
|
|
672
|
-
|
|
673
|
-
private updateStep(name: string, status: SetupStep["status"], message?: string): void {
|
|
674
|
-
const step = this.steps.find((s) => s.name === name)
|
|
675
|
-
if (step) {
|
|
676
|
-
step.status = status
|
|
677
|
-
step.message = message
|
|
678
|
-
}
|
|
679
|
-
}
|
|
680
|
-
|
|
681
|
-
private refreshContent(): void {
|
|
682
|
-
this.contentBox.getChildren().forEach((child) => child.destroy())
|
|
683
|
-
|
|
684
|
-
if (!this.isRunning && !this.isDone) {
|
|
685
|
-
// Show intro
|
|
686
|
-
this.contentBox.add(
|
|
687
|
-
new TextRenderable(this.cliRenderer, {
|
|
688
|
-
content: "This will automatically configure:\n\n",
|
|
689
|
-
fg: "#8be9fd",
|
|
690
|
-
})
|
|
691
|
-
)
|
|
692
|
-
this.steps.forEach((step) => {
|
|
693
|
-
this.contentBox.add(
|
|
694
|
-
new TextRenderable(this.cliRenderer, {
|
|
695
|
-
content: ` • ${step.name}\n`,
|
|
696
|
-
fg: "#aaaaaa",
|
|
697
|
-
})
|
|
698
|
-
)
|
|
699
|
-
})
|
|
700
|
-
this.contentBox.add(
|
|
701
|
-
new TextRenderable(this.cliRenderer, {
|
|
702
|
-
content: "\n\nPress Enter to start, Esc to go back.\n",
|
|
703
|
-
fg: "#50fa7b",
|
|
704
|
-
})
|
|
705
|
-
)
|
|
706
|
-
} else {
|
|
707
|
-
// Show progress
|
|
708
|
-
this.contentBox.add(
|
|
709
|
-
new TextRenderable(this.cliRenderer, {
|
|
710
|
-
content: this.isDone ? "Setup Complete!\n\n" : "Setting up...\n\n",
|
|
711
|
-
fg: this.isDone ? "#50fa7b" : "#f1fa8c",
|
|
712
|
-
})
|
|
713
|
-
)
|
|
714
|
-
|
|
715
|
-
this.steps.forEach((step) => {
|
|
716
|
-
let icon = "⏳"
|
|
717
|
-
let color = "#aaaaaa"
|
|
718
|
-
if (step.status === "success") {
|
|
719
|
-
icon = "✅"
|
|
720
|
-
color = "#50fa7b"
|
|
721
|
-
} else if (step.status === "error") {
|
|
722
|
-
icon = "❌"
|
|
723
|
-
color = "#ff5555"
|
|
724
|
-
} else if (step.status === "skipped") {
|
|
725
|
-
icon = "⏭️"
|
|
726
|
-
color = "#6272a4"
|
|
727
|
-
} else if (step.status === "running") {
|
|
728
|
-
icon = "🔄"
|
|
729
|
-
color = "#f1fa8c"
|
|
730
|
-
}
|
|
731
|
-
|
|
732
|
-
this.contentBox.add(
|
|
733
|
-
new TextRenderable(this.cliRenderer, {
|
|
734
|
-
content: `${icon} ${step.name}`,
|
|
735
|
-
fg: color,
|
|
736
|
-
})
|
|
737
|
-
)
|
|
738
|
-
if (step.message) {
|
|
739
|
-
this.contentBox.add(
|
|
740
|
-
new TextRenderable(this.cliRenderer, {
|
|
741
|
-
content: ` - ${step.message}`,
|
|
742
|
-
fg: "#6272a4",
|
|
743
|
-
})
|
|
744
|
-
)
|
|
745
|
-
}
|
|
746
|
-
this.contentBox.add(new TextRenderable(this.cliRenderer, { content: "\n", fg: "#aaaaaa" }))
|
|
747
|
-
})
|
|
748
|
-
|
|
749
|
-
if (this.isDone) {
|
|
750
|
-
this.contentBox.add(
|
|
751
|
-
new TextRenderable(this.cliRenderer, {
|
|
752
|
-
content: "\nPress Enter to go back.\n",
|
|
753
|
-
fg: "#50fa7b",
|
|
754
|
-
})
|
|
755
|
-
)
|
|
756
|
-
}
|
|
757
|
-
}
|
|
758
|
-
}
|
|
759
|
-
|
|
760
|
-
private cleanup(): void {
|
|
761
|
-
this.cliRenderer.keyInput.off("keypress", this.keyHandler)
|
|
762
|
-
debugLog("FullAutoSetup", "Key handler removed")
|
|
763
|
-
this.destroy()
|
|
764
|
-
this.onBack()
|
|
765
|
-
}
|
|
766
|
-
}
|