@muhammedaksam/easiarr 1.4.0 → 1.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. package/dist/index.js +29837 -0
  2. package/package.json +15 -15
  3. package/src/VersionInfo.ts +0 -12
  4. package/src/api/arr-api.ts +0 -521
  5. package/src/api/auto-setup-types.ts +0 -64
  6. package/src/api/base-api.ts +0 -216
  7. package/src/api/bazarr-api.ts +0 -297
  8. package/src/api/cloudflare-api.ts +0 -493
  9. package/src/api/custom-format-api.ts +0 -224
  10. package/src/api/grafana-api.ts +0 -230
  11. package/src/api/heimdall-api.ts +0 -141
  12. package/src/api/homarr-api.ts +0 -209
  13. package/src/api/huntarr-api.ts +0 -457
  14. package/src/api/index.ts +0 -9
  15. package/src/api/jellyfin-api.ts +0 -389
  16. package/src/api/jellyseerr-api.ts +0 -559
  17. package/src/api/maintainerr-api.ts +0 -461
  18. package/src/api/naming-config.ts +0 -101
  19. package/src/api/overseerr-api.ts +0 -392
  20. package/src/api/plex-api.ts +0 -308
  21. package/src/api/portainer-api.ts +0 -374
  22. package/src/api/profilarr-api.ts +0 -391
  23. package/src/api/prowlarr-api.ts +0 -488
  24. package/src/api/qbittorrent-api.ts +0 -300
  25. package/src/api/quality-profile-api.ts +0 -272
  26. package/src/api/tautulli-api.ts +0 -244
  27. package/src/api/uptime-kuma-api.ts +0 -343
  28. package/src/apps/categories.ts +0 -14
  29. package/src/apps/index.ts +0 -2
  30. package/src/apps/registry.ts +0 -1275
  31. package/src/compose/caddy-config.ts +0 -130
  32. package/src/compose/generator.ts +0 -287
  33. package/src/compose/index.ts +0 -7
  34. package/src/compose/templates.ts +0 -78
  35. package/src/compose/traefik-config.ts +0 -187
  36. package/src/config/bookmarks-generator.ts +0 -160
  37. package/src/config/defaults.ts +0 -37
  38. package/src/config/homepage-config.ts +0 -381
  39. package/src/config/index.ts +0 -6
  40. package/src/config/manager.ts +0 -150
  41. package/src/config/recyclarr-config.ts +0 -181
  42. package/src/config/schema.ts +0 -310
  43. package/src/config/slskd-config.ts +0 -86
  44. package/src/config/soularr-config.ts +0 -105
  45. package/src/config/trash-quality-definitions.ts +0 -213
  46. package/src/data/lidarr-custom-formats.ts +0 -127
  47. package/src/data/trash-profiles.ts +0 -333
  48. package/src/docker/client.ts +0 -312
  49. package/src/docker/index.ts +0 -18
  50. package/src/index.ts +0 -77
  51. package/src/setup/actions/arr-common.ts +0 -307
  52. package/src/setup/actions/dashboards.ts +0 -79
  53. package/src/setup/actions/download-clients.ts +0 -54
  54. package/src/setup/actions/jellyseerr.ts +0 -331
  55. package/src/setup/actions/media-servers.ts +0 -68
  56. package/src/setup/actions/monitoring.ts +0 -120
  57. package/src/setup/actions/prowlarr.ts +0 -137
  58. package/src/setup/actions/utilities.ts +0 -490
  59. package/src/setup/index.ts +0 -78
  60. package/src/setup/types.ts +0 -144
  61. package/src/structure/manager.ts +0 -129
  62. package/src/ui/App.ts +0 -111
  63. package/src/ui/components/ApplicationSelector.ts +0 -275
  64. package/src/ui/components/CredentialsForm.ts +0 -180
  65. package/src/ui/components/DownloadClientForm.ts +0 -114
  66. package/src/ui/components/FileEditor.ts +0 -91
  67. package/src/ui/components/FooterHint.ts +0 -119
  68. package/src/ui/components/PageLayout.ts +0 -160
  69. package/src/ui/components/UpdateNotification.ts +0 -102
  70. package/src/ui/index.ts +0 -7
  71. package/src/ui/screens/AdvancedSettings.ts +0 -188
  72. package/src/ui/screens/ApiKeyViewer.ts +0 -511
  73. package/src/ui/screens/AppConfigurator.ts +0 -543
  74. package/src/ui/screens/AppManager.ts +0 -284
  75. package/src/ui/screens/ContainerControl.ts +0 -581
  76. package/src/ui/screens/LogsViewer.ts +0 -478
  77. package/src/ui/screens/MainMenu.ts +0 -299
  78. package/src/ui/screens/MonitorDashboard.ts +0 -881
  79. package/src/ui/screens/SecretsEditor.ts +0 -216
  80. package/src/ui/screens/SettingsScreen.ts +0 -633
  81. package/src/ui/screens/index.ts +0 -22
  82. package/src/ui/screens/setup/BaseAppSetupScreen.ts +0 -375
  83. package/src/ui/screens/setup/CloudflaredSetup.ts +0 -460
  84. package/src/ui/screens/setup/FullAutoSetup.ts +0 -766
  85. package/src/ui/screens/setup/HomepageSetup.ts +0 -165
  86. package/src/ui/screens/setup/JellyfinSetup.ts +0 -328
  87. package/src/ui/screens/setup/JellyseerrSetup.ts +0 -242
  88. package/src/ui/screens/setup/ProwlarrSetup.ts +0 -500
  89. package/src/ui/screens/setup/QBittorrentSetup.ts +0 -221
  90. package/src/ui/screens/setup/QuickSetup.ts +0 -1169
  91. package/src/ui/screens/setup/RecyclarrSetup.ts +0 -270
  92. package/src/ui/screens/setup/TRaSHProfileSetup.ts +0 -381
  93. package/src/utils/arch.ts +0 -78
  94. package/src/utils/browser.ts +0 -27
  95. package/src/utils/categories.ts +0 -61
  96. package/src/utils/debug.ts +0 -84
  97. package/src/utils/env.ts +0 -138
  98. package/src/utils/index.ts +0 -8
  99. package/src/utils/logs.ts +0 -119
  100. package/src/utils/migrations/1765626338_rename_env_variables.ts +0 -102
  101. package/src/utils/migrations/1765707135_rename_easiarr_status.ts +0 -91
  102. package/src/utils/migrations/1765732722_remove_cloudflare_dns_api_token.ts +0 -45
  103. package/src/utils/migrations/1769515650_migrate_to_xdg.ts +0 -114
  104. package/src/utils/migrations.ts +0 -165
  105. package/src/utils/password.ts +0 -42
  106. package/src/utils/paths.ts +0 -33
  107. package/src/utils/unraid.ts +0 -103
  108. package/src/utils/update-checker.ts +0 -210
  109. package/src/utils/url-utils.ts +0 -38
@@ -1,490 +0,0 @@
1
- /**
2
- * Utility App Setup Actions
3
- *
4
- * Setup functions for Portainer, Cloudflare, Maintainerr, Bazarr,
5
- * Huntarr, Slskd, Soularr, Recyclarr, Profilarr, Overseerr, and other utilities.
6
- */
7
-
8
- import { existsSync } from "fs"
9
- import { mkdir, writeFile } from "fs/promises"
10
- import { dirname } from "path"
11
-
12
- import { BazarrApiClient } from "~/api/bazarr-api"
13
- import { CloudflareApi, setupCloudflaredTunnel } from "~/api/cloudflare-api"
14
- import { HuntarrClient } from "~/api/huntarr-api"
15
- import { MaintainerrClient } from "~/api/maintainerr-api"
16
- import { OverseerrClient } from "~/api/overseerr-api"
17
- import { PortainerApiClient } from "~/api/portainer-api"
18
- import { ProfilarrApiClient } from "~/api/profilarr-api"
19
- import { getApp } from "~/apps/registry"
20
- import { saveRecyclarrConfig } from "~/config/recyclarr-config"
21
- import { generateSlskdConfig, getSlskdConfigPath } from "~/config/slskd-config"
22
- import { generateSoularrConfig, getSoularrConfigPath } from "~/config/soularr-config"
23
- import { getEnabledAppConfig, SetupContext, SetupResult } from "~/setup/types"
24
- import { debugLog } from "~/utils/debug"
25
- import { getApplicationUrl } from "~/utils/url-utils"
26
-
27
- /**
28
- * Setup Portainer container management
29
- */
30
- export async function setupPortainer(ctx: SetupContext): Promise<SetupResult> {
31
- const portainerConfig = getEnabledAppConfig(ctx, "portainer")
32
- if (!portainerConfig) {
33
- return { success: false, message: "Not enabled" }
34
- }
35
-
36
- if (!ctx.globalPassword) {
37
- return { success: false, message: "No PASSWORD_GLOBAL set" }
38
- }
39
-
40
- const port = portainerConfig.port || 9000
41
- const client = new PortainerApiClient("localhost", port)
42
-
43
- try {
44
- const result = await client.setup({
45
- username: ctx.globalUsername,
46
- password: ctx.globalPassword,
47
- env: ctx.env,
48
- })
49
-
50
- return result
51
- } catch (e) {
52
- return { success: false, message: String(e) }
53
- }
54
- }
55
-
56
- /**
57
- * Setup Cloudflare Tunnel
58
- */
59
- export async function setupCloudflare(ctx: SetupContext): Promise<SetupResult> {
60
- const cloudflaredConfig = getEnabledAppConfig(ctx, "cloudflared")
61
- if (!cloudflaredConfig) {
62
- return { success: false, message: "Not enabled" }
63
- }
64
-
65
- const apiToken = ctx.env["CLOUDFLARE_API_TOKEN"]
66
- if (!apiToken) {
67
- return { success: false, message: "No CLOUDFLARE_API_TOKEN in .env" }
68
- }
69
-
70
- const domain = ctx.env["CLOUDFLARE_DNS_ZONE"] || ctx.config.traefik?.domain
71
- if (!domain) {
72
- return { success: false, message: "No domain configured" }
73
- }
74
-
75
- try {
76
- // Create/update tunnel
77
- const result = await setupCloudflaredTunnel(apiToken, domain, "easiarr")
78
-
79
- // Prepare env updates
80
- const envUpdates: Record<string, string> = {
81
- CLOUDFLARE_TUNNEL_TOKEN: result.tunnelToken,
82
- CLOUDFLARE_TUNNEL_ID: result.tunnelId,
83
- CLOUDFLARE_ACCOUNT_ID: result.accountId,
84
- CLOUDFLARE_DNS_ZONE: domain,
85
- }
86
-
87
- // Optional: Set up Cloudflare Access if email is available
88
- const accessEmail = ctx.env["CLOUDFLARE_ACCESS_EMAIL"] || ctx.env["EMAIL_GLOBAL"]
89
- if (accessEmail) {
90
- try {
91
- const api = new CloudflareApi(apiToken)
92
- await api.setupAccessProtection(domain, [accessEmail], "easiarr")
93
- return { success: true, message: `Tunnel + Access for ${accessEmail}`, envUpdates }
94
- } catch {
95
- return { success: true, message: "Tunnel created (Access failed)", envUpdates }
96
- }
97
- }
98
-
99
- return { success: true, message: "Tunnel created", envUpdates }
100
- } catch (e) {
101
- return { success: false, message: String(e) }
102
- }
103
- }
104
-
105
- /**
106
- * Setup Overseerr request management
107
- */
108
- export async function setupOverseerr(ctx: SetupContext): Promise<SetupResult> {
109
- const overseerrConfig = getEnabledAppConfig(ctx, "overseerr")
110
- if (!overseerrConfig) {
111
- return { success: false, message: "Not enabled" }
112
- }
113
-
114
- // Overseerr requires Plex
115
- const plexConfig = getEnabledAppConfig(ctx, "plex")
116
- if (!plexConfig) {
117
- return { success: false, message: "Plex not enabled" }
118
- }
119
-
120
- const plexToken = ctx.env["API_KEY_PLEX"]
121
- if (!plexToken) {
122
- return { success: false, message: "No API_KEY_PLEX in .env" }
123
- }
124
-
125
- const port = overseerrConfig.port || 5055
126
- const client = new OverseerrClient("localhost", port)
127
-
128
- try {
129
- const result = await client.setup({
130
- username: ctx.globalUsername,
131
- password: ctx.globalPassword,
132
- env: ctx.env,
133
- plexToken,
134
- })
135
-
136
- if (result.success) {
137
- // Set Overseerr's applicationUrl
138
- try {
139
- const overseerrUrl = getApplicationUrl("overseerr", port, ctx.config)
140
- await client.setApplicationUrl(overseerrUrl)
141
- debugLog("OverseerrSetup", `applicationUrl set to ${overseerrUrl}`)
142
- } catch {
143
- debugLog("OverseerrSetup", "Failed to set applicationUrl")
144
- }
145
- }
146
-
147
- return result
148
- } catch (e) {
149
- return { success: false, message: String(e) }
150
- }
151
- }
152
-
153
- /**
154
- * Setup Maintainerr for media maintenance
155
- */
156
- export async function setupMaintainerr(ctx: SetupContext): Promise<SetupResult> {
157
- const maintainerrConfig = getEnabledAppConfig(ctx, "maintainerr")
158
- if (!maintainerrConfig) {
159
- return { success: false, message: "Not enabled" }
160
- }
161
-
162
- // Requires Plex
163
- const plexConfig = getEnabledAppConfig(ctx, "plex")
164
- if (!plexConfig) {
165
- return { success: false, message: "Plex not enabled" }
166
- }
167
-
168
- const port = maintainerrConfig.port || 6246
169
- const client = new MaintainerrClient("localhost", port)
170
-
171
- try {
172
- const result = await client.setup({
173
- username: ctx.globalUsername,
174
- password: ctx.globalPassword,
175
- env: ctx.env,
176
- plexToken: ctx.env["API_KEY_PLEX"],
177
- })
178
-
179
- if (result.success) {
180
- // Configure Radarr connection if enabled
181
- const radarrConfig = getEnabledAppConfig(ctx, "radarr")
182
- if (radarrConfig && ctx.env["API_KEY_RADARR"]) {
183
- try {
184
- const radarrDef = getApp("radarr")
185
- const radarrPort = radarrConfig.port || radarrDef?.defaultPort || 7878
186
- await client.configureRadarr("radarr", radarrPort, ctx.env["API_KEY_RADARR"])
187
- } catch {
188
- /* connection failed */
189
- }
190
- }
191
-
192
- // Configure Sonarr connection if enabled
193
- const sonarrConfig = getEnabledAppConfig(ctx, "sonarr")
194
- if (sonarrConfig && ctx.env["API_KEY_SONARR"]) {
195
- try {
196
- const sonarrDef = getApp("sonarr")
197
- const sonarrPort = sonarrConfig.port || sonarrDef?.defaultPort || 8989
198
- await client.configureSonarr("sonarr", sonarrPort, ctx.env["API_KEY_SONARR"])
199
- } catch {
200
- /* connection failed */
201
- }
202
- }
203
-
204
- // Configure Overseerr connection if enabled
205
- const overseerrConfig = getEnabledAppConfig(ctx, "overseerr")
206
- if (overseerrConfig && ctx.env["API_KEY_OVERSEERR"]) {
207
- try {
208
- const overseerrDef = getApp("overseerr")
209
- const overseerrPort = overseerrConfig.port || overseerrDef?.defaultPort || 5055
210
- await client.configureOverseerr("overseerr", overseerrPort, ctx.env["API_KEY_OVERSEERR"])
211
- } catch {
212
- /* connection failed */
213
- }
214
- }
215
-
216
- // Configure Tautulli connection if enabled
217
- const tautulliConfig = getEnabledAppConfig(ctx, "tautulli")
218
- if (tautulliConfig && ctx.env["API_KEY_TAUTULLI"]) {
219
- try {
220
- const tautulliDef = getApp("tautulli")
221
- const tautulliPort = tautulliConfig.port || tautulliDef?.defaultPort || 8181
222
- await client.configureTautulli("tautulli", tautulliPort, ctx.env["API_KEY_TAUTULLI"])
223
- } catch {
224
- /* connection failed */
225
- }
226
- }
227
- }
228
-
229
- return result
230
- } catch (e) {
231
- return { success: false, message: String(e) }
232
- }
233
- }
234
-
235
- /**
236
- * Setup Bazarr subtitle management
237
- */
238
- export async function setupBazarr(ctx: SetupContext): Promise<SetupResult> {
239
- const bazarrConfig = getEnabledAppConfig(ctx, "bazarr")
240
- if (!bazarrConfig) {
241
- return { success: false, message: "Not enabled" }
242
- }
243
-
244
- const port = bazarrConfig.port || 6767
245
- const client = new BazarrApiClient("localhost", port)
246
-
247
- // Get and set API key if available
248
- const existingApiKey = ctx.env["API_KEY_BAZARR"]
249
- if (existingApiKey) {
250
- client.setApiKey(existingApiKey)
251
- }
252
-
253
- try {
254
- const result = await client.setup({
255
- username: ctx.globalUsername,
256
- password: ctx.globalPassword,
257
- env: ctx.env,
258
- })
259
-
260
- if (result.success) {
261
- // Configure Radarr/Sonarr connections
262
- let configured = 0
263
- const radarrConfig = getEnabledAppConfig(ctx, "radarr")
264
- if (radarrConfig && ctx.env["API_KEY_RADARR"]) {
265
- try {
266
- await client.configureRadarr(
267
- "radarr",
268
- radarrConfig.port || 7878,
269
- ctx.env["API_KEY_RADARR"]
270
- )
271
- configured++
272
- } catch {
273
- /* connection failed */
274
- }
275
- }
276
-
277
- const sonarrConfig = getEnabledAppConfig(ctx, "sonarr")
278
- if (sonarrConfig && ctx.env["API_KEY_SONARR"]) {
279
- try {
280
- await client.configureSonarr(
281
- "sonarr",
282
- sonarrConfig.port || 8989,
283
- ctx.env["API_KEY_SONARR"]
284
- )
285
- configured++
286
- } catch {
287
- /* connection failed */
288
- }
289
- }
290
-
291
- return {
292
- ...result,
293
- message: configured > 0 ? `${configured} apps connected` : result.message,
294
- }
295
- }
296
-
297
- return result
298
- } catch (e) {
299
- return { success: false, message: String(e) }
300
- }
301
- }
302
-
303
- /**
304
- * Setup Huntarr for automatic searches
305
- */
306
- export async function setupHuntarr(ctx: SetupContext): Promise<SetupResult> {
307
- const huntarrConfig = getEnabledAppConfig(ctx, "huntarr")
308
- if (!huntarrConfig) {
309
- return { success: false, message: "Not enabled" }
310
- }
311
-
312
- const port = huntarrConfig.port || 9705
313
- const client = new HuntarrClient("localhost", port)
314
-
315
- // Check if reachable
316
- const healthy = await client.isHealthy()
317
- if (!healthy) {
318
- return { success: false, message: "Not reachable yet" }
319
- }
320
-
321
- try {
322
- // Authenticate (creates user if needed, otherwise logs in)
323
- const authenticated = await client.authenticate(ctx.globalUsername, ctx.globalPassword)
324
- if (!authenticated) {
325
- return { success: false, message: "Auth failed" }
326
- }
327
-
328
- // Add enabled *arr apps to Huntarr
329
- const result = await client.setupEasiarrApps(ctx.config.apps, ctx.env)
330
- return { success: true, message: `${result.added} *arr apps added` }
331
- } catch (e) {
332
- return { success: false, message: String(e) }
333
- }
334
- }
335
-
336
- /**
337
- * Setup Slskd for Soulseek integration
338
- */
339
- export async function setupSlskd(ctx: SetupContext): Promise<SetupResult> {
340
- const slskdConfig = getEnabledAppConfig(ctx, "slskd")
341
- if (!slskdConfig) {
342
- return { success: false, message: "Not enabled" }
343
- }
344
-
345
- try {
346
- // Generate slskd.yml config with auto-generated API key
347
- const { yaml, apiKey } = generateSlskdConfig(ctx.config)
348
- const configPath = getSlskdConfigPath(ctx.config.rootDir)
349
-
350
- // Ensure config directory exists
351
- const configDir = dirname(configPath)
352
- if (!existsSync(configDir)) {
353
- await mkdir(configDir, { recursive: true })
354
- }
355
-
356
- // Create slskd download directories
357
- const slskdDownloadsDir = `${ctx.config.rootDir}/data/slskd_downloads`
358
- await mkdir(`${slskdDownloadsDir}/incomplete`, { recursive: true })
359
- await mkdir(`${slskdDownloadsDir}/complete`, { recursive: true })
360
-
361
- // Write slskd.yml
362
- await writeFile(configPath, yaml)
363
-
364
- return {
365
- success: true,
366
- message: "Config generated, API key saved",
367
- envUpdates: { API_KEY_SLSKD: apiKey },
368
- }
369
- } catch (e) {
370
- return { success: false, message: String(e) }
371
- }
372
- }
373
-
374
- /**
375
- * Setup Soularr for Lidarr/Slskd integration
376
- */
377
- export async function setupSoularr(ctx: SetupContext): Promise<SetupResult> {
378
- const soularrConfig = getEnabledAppConfig(ctx, "soularr")
379
- if (!soularrConfig) {
380
- return { success: false, message: "Not enabled" }
381
- }
382
-
383
- // Check dependencies
384
- const lidarrConfig = getEnabledAppConfig(ctx, "lidarr")
385
- const slskdConfig = getEnabledAppConfig(ctx, "slskd")
386
-
387
- if (!lidarrConfig || !slskdConfig) {
388
- return { success: false, message: "Requires Lidarr & Slskd" }
389
- }
390
-
391
- try {
392
- // Generate soularr config.ini
393
- const configContent = generateSoularrConfig(ctx.config)
394
- const configPath = getSoularrConfigPath(ctx.config.rootDir)
395
-
396
- // Ensure directory exists
397
- const configDir = dirname(configPath)
398
- if (!existsSync(configDir)) {
399
- await mkdir(configDir, { recursive: true })
400
- }
401
-
402
- // Write config file
403
- await writeFile(configPath, configContent)
404
-
405
- return { success: true, message: "Config generated" }
406
- } catch (e) {
407
- return { success: false, message: String(e) }
408
- }
409
- }
410
-
411
- /**
412
- * Setup Recyclarr for TRaSH guide syncing
413
- */
414
- export async function setupRecyclarr(ctx: SetupContext): Promise<SetupResult> {
415
- const recyclarrConfig = getEnabledAppConfig(ctx, "recyclarr")
416
- if (!recyclarrConfig) {
417
- return { success: false, message: "Not enabled" }
418
- }
419
-
420
- // Check if we have at least one *arr app with API key
421
- const radarrApiKey = ctx.env["API_KEY_RADARR"]
422
- const sonarrApiKey = ctx.env["API_KEY_SONARR"]
423
-
424
- if (!radarrApiKey && !sonarrApiKey) {
425
- return { success: false, message: "No Radarr/Sonarr API keys" }
426
- }
427
-
428
- try {
429
- await saveRecyclarrConfig(ctx.config)
430
- return { success: true, message: "Config generated" }
431
- } catch (e) {
432
- return { success: false, message: String(e) }
433
- }
434
- }
435
-
436
- /**
437
- * Setup Profilarr for TRaSH profile management
438
- */
439
- export async function setupProfilarr(ctx: SetupContext): Promise<SetupResult> {
440
- const profilarrConfig = getEnabledAppConfig(ctx, "profilarr")
441
- if (!profilarrConfig) {
442
- return { success: false, message: "Not enabled" }
443
- }
444
-
445
- const port = profilarrConfig.port || 6868
446
- const client = new ProfilarrApiClient("localhost", port)
447
-
448
- // Check if reachable
449
- const healthy = await client.isHealthy()
450
- if (!healthy) {
451
- return { success: false, message: "Not reachable yet" }
452
- }
453
-
454
- try {
455
- // Run the auto-setup process
456
- const result = await client.setup({
457
- username: ctx.globalUsername,
458
- password: ctx.globalPassword,
459
- env: ctx.env,
460
- })
461
-
462
- if (result.success) {
463
- // Configure Radarr if enabled
464
- const radarrConfig = getEnabledAppConfig(ctx, "radarr")
465
- if (radarrConfig && ctx.env["API_KEY_RADARR"]) {
466
- try {
467
- const radarrPort = radarrConfig.port || 7878
468
- await client.configureRadarr("radarr", radarrPort, ctx.env["API_KEY_RADARR"])
469
- } catch {
470
- /* connection failed */
471
- }
472
- }
473
-
474
- // Configure Sonarr if enabled
475
- const sonarrConfig = getEnabledAppConfig(ctx, "sonarr")
476
- if (sonarrConfig && ctx.env["API_KEY_SONARR"]) {
477
- try {
478
- const sonarrPort = sonarrConfig.port || 8989
479
- await client.configureSonarr("sonarr", sonarrPort, ctx.env["API_KEY_SONARR"])
480
- } catch {
481
- /* connection failed */
482
- }
483
- }
484
- }
485
-
486
- return result
487
- } catch (e) {
488
- return { success: false, message: String(e) }
489
- }
490
- }
@@ -1,78 +0,0 @@
1
- /**
2
- * Setup Actions
3
- *
4
- * Reusable setup functions for all easiarr apps.
5
- * Import from here rather than individual action files.
6
- *
7
- * @example
8
- * ```ts
9
- * import { runJellyseerrFullSetup, createSetupContext } from "~/setup"
10
- *
11
- * const ctx = createSetupContext(config, env)
12
- * const result = await runJellyseerrFullSetup(ctx)
13
- * ```
14
- */
15
-
16
- // Core types
17
- export type { SetupContext, SetupResult, SetupStep, SetupStepStatus } from "./types"
18
-
19
- // Core functions
20
- export { reportStep, createSetupContext, isAppEnabled, getEnabledAppConfig } from "./types"
21
-
22
- // Arr common actions (root folders, naming, quality, auth, external URLs)
23
- export {
24
- setupArrRootFolders,
25
- setupArrNaming,
26
- setupArrQuality,
27
- setupArrAuthentication,
28
- setupBazarrAuthentication,
29
- setupArrExternalUrls,
30
- } from "./actions/arr-common"
31
-
32
- // Jellyseerr actions
33
- export {
34
- checkJellyseerrPrerequisites,
35
- createJellyseerrClient,
36
- runJellyseerrWizard,
37
- configureJellyseerrRadarr,
38
- configureJellyseerrSonarr,
39
- setJellyseerrExternalUrl,
40
- setJellyseerrJellyfinUrl,
41
- syncJellyseerrLibraries,
42
- runJellyseerrFullSetup,
43
- type JellyseerrSetupOptions,
44
- } from "./actions/jellyseerr"
45
-
46
- // Prowlarr actions
47
- export {
48
- createProwlarrClient,
49
- setupProwlarrApps,
50
- setupFlareSolverr,
51
- runProwlarrFullSetup,
52
- } from "./actions/prowlarr"
53
-
54
- // Download client actions
55
- export { setupQBittorrent } from "./actions/download-clients"
56
-
57
- // Media server actions
58
- export { setupJellyfin, setupPlex } from "./actions/media-servers"
59
-
60
- // Monitoring actions
61
- export { setupUptimeKuma, setupGrafana, setupTautulli } from "./actions/monitoring"
62
-
63
- // Dashboard actions
64
- export { setupHomarr, setupHeimdall } from "./actions/dashboards"
65
-
66
- // Utility actions
67
- export {
68
- setupPortainer,
69
- setupCloudflare,
70
- setupOverseerr,
71
- setupMaintainerr,
72
- setupBazarr,
73
- setupHuntarr,
74
- setupSlskd,
75
- setupSoularr,
76
- setupRecyclarr,
77
- setupProfilarr,
78
- } from "./actions/utilities"
@@ -1,144 +0,0 @@
1
- /**
2
- * Setup Types
3
- *
4
- * Core types shared by all setup actions.
5
- * These enable code reuse between FullAutoSetup and individual app screens.
6
- */
7
-
8
- import { EasiarrConfig } from "~/config/schema"
9
-
10
- /**
11
- * Context passed to all setup actions.
12
- * Contains everything needed to configure an app.
13
- */
14
- export interface SetupContext {
15
- /** The current easiarr configuration */
16
- config: EasiarrConfig
17
-
18
- /** Environment variables from .env file */
19
- env: Record<string, string>
20
-
21
- /** Global username for authentication (from USERNAME_GLOBAL) */
22
- globalUsername: string
23
-
24
- /** Global password for authentication (from PASSWORD_GLOBAL) */
25
- globalPassword: string
26
-
27
- /**
28
- * Optional callback when a step starts.
29
- * Used by UI to show "running" status.
30
- */
31
- onStepStart?: (stepName: string) => void
32
-
33
- /**
34
- * Optional callback when a step completes.
35
- * Used by UI to show success/error/skipped status.
36
- */
37
- onStepComplete?: (step: SetupStep) => void
38
- }
39
-
40
- /**
41
- * Status of a single step in a setup action.
42
- */
43
- export type SetupStepStatus = "pending" | "running" | "success" | "error" | "skipped"
44
-
45
- /**
46
- * Represents a single step in a multi-step setup action.
47
- */
48
- export interface SetupStep {
49
- /** Human-readable name of the step */
50
- name: string
51
-
52
- /** Current status of the step */
53
- status: SetupStepStatus
54
-
55
- /** Optional message (e.g., error details, success info) */
56
- message?: string
57
- }
58
-
59
- /**
60
- * Result returned from a setup action.
61
- */
62
- export interface SetupResult {
63
- /** Whether the action succeeded */
64
- success: boolean
65
-
66
- /** Human-readable message describing the result */
67
- message?: string
68
-
69
- /**
70
- * Environment variable updates to persist to .env file.
71
- * Caller is responsible for persisting these.
72
- */
73
- envUpdates?: Record<string, string>
74
-
75
- /**
76
- * Additional data returned by the action.
77
- * Type depends on the specific action.
78
- */
79
- data?: unknown
80
- }
81
-
82
- /**
83
- * Helper to report step progress during multi-step actions.
84
- *
85
- * @example
86
- * ```ts
87
- * reportStep(ctx, "Configure Radarr", "running")
88
- * const result = await configureRadarr(ctx)
89
- * reportStep(ctx, "Configure Radarr", result.success ? "success" : "error", result.message)
90
- * ```
91
- */
92
- export function reportStep(
93
- ctx: SetupContext,
94
- name: string,
95
- status: SetupStepStatus,
96
- message?: string
97
- ): void {
98
- if (status === "running") {
99
- ctx.onStepStart?.(name)
100
- }
101
- ctx.onStepComplete?.({ name, status, message })
102
- }
103
-
104
- /**
105
- * Creates a SetupContext from common sources.
106
- *
107
- * @param config - The easiarr configuration
108
- * @param env - Environment variables (typically from readEnvSync())
109
- * @param callbacks - Optional progress callbacks
110
- */
111
- export function createSetupContext(
112
- config: EasiarrConfig,
113
- env: Record<string, string>,
114
- callbacks?: {
115
- onStepStart?: (stepName: string) => void
116
- onStepComplete?: (step: SetupStep) => void
117
- }
118
- ): SetupContext {
119
- return {
120
- config,
121
- env,
122
- globalUsername: env["USERNAME_GLOBAL"] || "admin",
123
- globalPassword: env["PASSWORD_GLOBAL"] || "",
124
- onStepStart: callbacks?.onStepStart,
125
- onStepComplete: callbacks?.onStepComplete,
126
- }
127
- }
128
-
129
- /**
130
- * Helper to check if an app is enabled in the config.
131
- */
132
- export function isAppEnabled(ctx: SetupContext, appId: string): boolean {
133
- return ctx.config.apps.some((a) => a.id === appId && a.enabled)
134
- }
135
-
136
- /**
137
- * Helper to get app config if enabled.
138
- */
139
- export function getEnabledAppConfig(
140
- ctx: SetupContext,
141
- appId: string
142
- ): EasiarrConfig["apps"][number] | undefined {
143
- return ctx.config.apps.find((a) => a.id === appId && a.enabled)
144
- }