@muhammedaksam/easiarr 1.4.0 → 1.6.0

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 +29750 -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,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
- }