@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
package/src/index.ts DELETED
@@ -1,77 +0,0 @@
1
- #!/usr/bin/env bun
2
- /**
3
- * easiarr Entry Point
4
- * TUI tool for generating docker-compose files for the *arr ecosystem
5
- *
6
- * Usage:
7
- * easiarr - Start the TUI
8
- * easiarr --debug - Start with debug logging enabled
9
- * easiarr -d - Same as --debug
10
- */
11
- import { createCliRenderer } from "@opentui/core"
12
-
13
- import { App } from "./ui/App"
14
- import { initDebug } from "./utils/debug"
15
- import { runMigrations } from "./utils/migrations"
16
-
17
- async function main() {
18
- // Initialize debug logging if enabled
19
- initDebug()
20
-
21
- // Run migrations to update env variable names if needed
22
- await runMigrations()
23
-
24
- const renderer = await createCliRenderer({
25
- consoleOptions: {
26
- startInDebugMode: false,
27
- },
28
- exitOnCtrlC: true,
29
- })
30
-
31
- // Cleanup function to properly restore terminal state
32
- let isCleanedUp = false
33
- const cleanup = () => {
34
- if (isCleanedUp) return
35
- isCleanedUp = true
36
-
37
- try {
38
- // Destroy renderer to restore terminal state (disables mouse tracking, restores cursor, etc.)
39
- if (renderer && typeof renderer.destroy === "function") {
40
- renderer.destroy()
41
- }
42
- } catch {
43
- // Ignore errors during cleanup
44
- }
45
- }
46
-
47
- // Register cleanup handlers for various exit scenarios
48
- process.on("exit", () => {
49
- cleanup()
50
- })
51
- process.on("SIGINT", () => {
52
- cleanup()
53
- process.exit(0)
54
- })
55
- process.on("SIGTERM", () => {
56
- cleanup()
57
- process.exit(0)
58
- })
59
- process.on("uncaughtException", (error) => {
60
- console.error("Uncaught exception:", error)
61
- cleanup()
62
- process.exit(1)
63
- })
64
- process.on("unhandledRejection", (reason) => {
65
- console.error("Unhandled rejection:", reason)
66
- cleanup()
67
- process.exit(1)
68
- })
69
-
70
- const app = new App(renderer)
71
- await app.start()
72
- }
73
-
74
- main().catch((error) => {
75
- console.error("Fatal error:", error)
76
- process.exit(1)
77
- })
@@ -1,307 +0,0 @@
1
- /**
2
- * Arr Common Setup Actions
3
- *
4
- * Shared setup functions for *arr apps (Radarr, Sonarr, Lidarr, Readarr, Whisparr, Prowlarr).
5
- * Includes: root folders, naming, quality, authentication, external URLs.
6
- */
7
-
8
- import { AddRootFolderOptions, ArrApiClient } from "~/api/arr-api"
9
- import { BazarrApiClient } from "~/api/bazarr-api"
10
- import { QualityProfileClient } from "~/api/quality-profile-api"
11
- import { getApp } from "~/apps/registry"
12
- import { getEnabledAppConfig, SetupContext, SetupResult } from "~/setup/types"
13
- import { debugLog } from "~/utils/debug"
14
- import { getApplicationUrl } from "~/utils/url-utils"
15
-
16
- type NamingAppId = "radarr" | "sonarr" | "lidarr"
17
-
18
- /**
19
- * Get all enabled *arr apps that have root folder configuration
20
- */
21
- function getArrAppsWithRootFolder(ctx: SetupContext) {
22
- return ctx.config.apps.filter((a) => {
23
- const def = getApp(a.id)
24
- return a.enabled && def?.rootFolder
25
- })
26
- }
27
-
28
- /**
29
- * Get enabled *arr apps that support naming configuration
30
- */
31
- function getNamingApps(ctx: SetupContext) {
32
- return ctx.config.apps.filter((a) => {
33
- return a.enabled && (a.id === "radarr" || a.id === "sonarr" || a.id === "lidarr")
34
- })
35
- }
36
-
37
- // ============================================
38
- // ROOT FOLDERS
39
- // ============================================
40
-
41
- /**
42
- * Setup root folders for all enabled *arr apps
43
- */
44
- export async function setupArrRootFolders(ctx: SetupContext): Promise<SetupResult> {
45
- const arrApps = getArrAppsWithRootFolder(ctx)
46
-
47
- if (arrApps.length === 0) {
48
- return { success: true, message: "No *arr apps enabled" }
49
- }
50
-
51
- let configured = 0
52
- const errors: string[] = []
53
-
54
- for (const app of arrApps) {
55
- const def = getApp(app.id)
56
- if (!def?.rootFolder) continue
57
-
58
- const apiKey = ctx.env[`API_KEY_${app.id.toUpperCase()}`]
59
- if (!apiKey) continue
60
-
61
- const port = app.port || def.defaultPort
62
- const client = new ArrApiClient("localhost", port, apiKey, def.rootFolder.apiVersion)
63
-
64
- try {
65
- const existing = await client.getRootFolders()
66
- if (existing.length === 0) {
67
- const options: AddRootFolderOptions = { path: def.rootFolder.path }
68
- if (app.id === "lidarr") options.name = "Music"
69
- await client.addRootFolder(options)
70
- configured++
71
- }
72
- } catch (e) {
73
- errors.push(`${app.id}: ${e}`)
74
- }
75
- }
76
-
77
- if (errors.length > 0) {
78
- return { success: configured > 0, message: `${configured} configured, ${errors.length} failed` }
79
- }
80
-
81
- return { success: true, message: `${configured || arrApps.length} apps configured` }
82
- }
83
-
84
- // ============================================
85
- // NAMING SCHEME
86
- // ============================================
87
-
88
- /**
89
- * Configure TRaSH naming scheme for Radarr, Sonarr, and Lidarr
90
- */
91
- export async function setupArrNaming(ctx: SetupContext): Promise<SetupResult> {
92
- const arrApps = getNamingApps(ctx)
93
-
94
- if (arrApps.length === 0) {
95
- return { success: true, message: "No apps need naming config" }
96
- }
97
-
98
- let configured = 0
99
-
100
- for (const app of arrApps) {
101
- const apiKey = ctx.env[`API_KEY_${app.id.toUpperCase()}`]
102
- if (!apiKey) continue
103
-
104
- const def = getApp(app.id)
105
- if (!def) continue
106
-
107
- const port = app.port || def.defaultPort
108
- const client = new ArrApiClient("localhost", port, apiKey, def.rootFolder?.apiVersion || "v3")
109
-
110
- try {
111
- await client.configureTRaSHNaming(app.id as NamingAppId)
112
- debugLog("ArrSetup", `Configured naming for ${app.id}`)
113
- configured++
114
- } catch (e) {
115
- debugLog("ArrSetup", `Failed to configure naming for ${app.id}: ${e}`)
116
- }
117
- }
118
-
119
- return { success: true, message: `${configured} apps configured` }
120
- }
121
-
122
- // ============================================
123
- // QUALITY SETTINGS
124
- // ============================================
125
-
126
- /**
127
- * Configure TRaSH quality definitions for Radarr, Sonarr, and Lidarr
128
- */
129
- export async function setupArrQuality(ctx: SetupContext): Promise<SetupResult> {
130
- const arrApps = getNamingApps(ctx)
131
-
132
- if (arrApps.length === 0) {
133
- return { success: true, message: "No apps need quality config" }
134
- }
135
-
136
- let configured = 0
137
-
138
- for (const app of arrApps) {
139
- const apiKey = ctx.env[`API_KEY_${app.id.toUpperCase()}`]
140
- if (!apiKey) continue
141
-
142
- const def = getApp(app.id)
143
- if (!def) continue
144
-
145
- const port = app.port || def.defaultPort
146
- const apiVersion = def.rootFolder?.apiVersion || "v3"
147
- const client = new QualityProfileClient("localhost", port, apiKey, apiVersion)
148
-
149
- try {
150
- await client.updateTrashQualityDefinitions(app.id as NamingAppId)
151
- debugLog("ArrSetup", `Configured quality settings for ${app.id}`)
152
- configured++
153
- } catch (e) {
154
- debugLog("ArrSetup", `Failed to configure quality settings for ${app.id}: ${e}`)
155
- }
156
- }
157
-
158
- return { success: true, message: `${configured} apps configured` }
159
- }
160
-
161
- // ============================================
162
- // AUTHENTICATION
163
- // ============================================
164
-
165
- /**
166
- * Setup form authentication for all *arr apps and Bazarr
167
- */
168
- export async function setupArrAuthentication(ctx: SetupContext): Promise<SetupResult> {
169
- if (!ctx.globalPassword) {
170
- return { success: false, message: "No PASSWORD_GLOBAL set" }
171
- }
172
-
173
- let configured = 0
174
-
175
- // Setup *arr apps (Radarr, Sonarr, Lidarr, etc.) with form auth
176
- const arrApps = ctx.config.apps.filter((a) => {
177
- const def = getApp(a.id)
178
- return a.enabled && (def?.rootFolder || a.id === "prowlarr")
179
- })
180
-
181
- for (const app of arrApps) {
182
- const def = getApp(app.id)
183
- if (!def) continue
184
-
185
- const apiKey = ctx.env[`API_KEY_${app.id.toUpperCase()}`]
186
- if (!apiKey) continue
187
-
188
- const port = app.port || def.defaultPort
189
- const apiVersion = app.id === "prowlarr" ? "v1" : def.rootFolder?.apiVersion || "v3"
190
- const client = new ArrApiClient("localhost", port, apiKey, apiVersion)
191
-
192
- try {
193
- await client.updateHostConfig(ctx.globalUsername, ctx.globalPassword, false)
194
- configured++
195
- } catch {
196
- // Skip individual failures
197
- }
198
- }
199
-
200
- // Setup Bazarr form authentication
201
- const bazarrResult = await setupBazarrAuthentication(ctx)
202
-
203
- return {
204
- success: true,
205
- message: bazarrResult.success
206
- ? `${configured} *arr apps + Bazarr configured`
207
- : `${configured} *arr apps configured`,
208
- }
209
- }
210
-
211
- /**
212
- * Setup Bazarr authentication and connections to Radarr/Sonarr
213
- */
214
- export async function setupBazarrAuthentication(ctx: SetupContext): Promise<SetupResult> {
215
- const bazarrConfig = getEnabledAppConfig(ctx, "bazarr")
216
- if (!bazarrConfig) {
217
- return { success: false, message: "Bazarr not enabled" }
218
- }
219
-
220
- const bazarrApiKey = ctx.env["API_KEY_BAZARR"]
221
- if (!bazarrApiKey) {
222
- return { success: false, message: "No Bazarr API key" }
223
- }
224
-
225
- const bazarrDef = getApp("bazarr")
226
- const bazarrPort = bazarrConfig.port || bazarrDef?.defaultPort || 6767
227
- const bazarrClient = new BazarrApiClient("localhost", bazarrPort)
228
- bazarrClient.setApiKey(bazarrApiKey)
229
-
230
- try {
231
- // Enable form auth
232
- if (ctx.globalPassword) {
233
- await bazarrClient.enableFormAuth(ctx.globalUsername, ctx.globalPassword, false)
234
- }
235
-
236
- // Configure Radarr connection
237
- const radarrConfig = getEnabledAppConfig(ctx, "radarr")
238
- const radarrApiKey = ctx.env["API_KEY_RADARR"]
239
- if (radarrConfig && radarrApiKey) {
240
- const radarrDef = getApp("radarr")
241
- const radarrPort = radarrConfig.port || radarrDef?.defaultPort || 7878
242
- await bazarrClient.configureRadarr("radarr", radarrPort, radarrApiKey)
243
- debugLog("BazarrSetup", "Bazarr -> Radarr connection configured")
244
- }
245
-
246
- // Configure Sonarr connection
247
- const sonarrConfig = getEnabledAppConfig(ctx, "sonarr")
248
- const sonarrApiKey = ctx.env["API_KEY_SONARR"]
249
- if (sonarrConfig && sonarrApiKey) {
250
- const sonarrDef = getApp("sonarr")
251
- const sonarrPort = sonarrConfig.port || sonarrDef?.defaultPort || 8989
252
- await bazarrClient.configureSonarr("sonarr", sonarrPort, sonarrApiKey)
253
- debugLog("BazarrSetup", "Bazarr -> Sonarr connection configured")
254
- }
255
-
256
- // TRaSH Recommended Settings
257
- await bazarrClient.configureGeneralSettings()
258
- await bazarrClient.configureDefaultLanguageProfile()
259
-
260
- return { success: true, message: "Bazarr configured" }
261
- } catch (e) {
262
- return { success: false, message: String(e) }
263
- }
264
- }
265
-
266
- // ============================================
267
- // EXTERNAL URLS
268
- // ============================================
269
-
270
- /**
271
- * Set applicationUrl for all *arr apps
272
- */
273
- export async function setupArrExternalUrls(ctx: SetupContext): Promise<SetupResult> {
274
- const arrApps = ctx.config.apps.filter((a) => {
275
- const def = getApp(a.id)
276
- return a.enabled && (def?.rootFolder || a.id === "prowlarr")
277
- })
278
-
279
- let configured = 0
280
-
281
- for (const app of arrApps) {
282
- const def = getApp(app.id)
283
- if (!def) continue
284
-
285
- const apiKey = ctx.env[`API_KEY_${app.id.toUpperCase()}`]
286
- if (!apiKey) continue
287
-
288
- const port = app.port || def.defaultPort
289
- const apiVersion = app.id === "prowlarr" ? "v1" : def.rootFolder?.apiVersion || "v3"
290
- const client = new ArrApiClient("localhost", port, apiKey, apiVersion)
291
-
292
- try {
293
- const applicationUrl = getApplicationUrl(app.id, port, ctx.config)
294
- await client.setApplicationUrl(applicationUrl)
295
- debugLog("ArrSetup", `Set applicationUrl for ${app.id}: ${applicationUrl}`)
296
- configured++
297
- } catch (e) {
298
- debugLog("ArrSetup", `Failed to set applicationUrl for ${app.id}: ${e}`)
299
- }
300
- }
301
-
302
- if (configured > 0) {
303
- return { success: true, message: `${configured} apps configured` }
304
- }
305
-
306
- return { success: false, message: "No apps with API keys" }
307
- }
@@ -1,79 +0,0 @@
1
- /**
2
- * Dashboard App Setup Actions
3
- *
4
- * Setup functions for Homarr, Heimdall, Homepage, and other dashboards.
5
- */
6
-
7
- import { HeimdallClient } from "~/api/heimdall-api"
8
- import { HomarrClient } from "~/api/homarr-api"
9
- import { getEnabledAppConfig, SetupContext, SetupResult } from "~/setup/types"
10
-
11
- /**
12
- * Setup Homarr dashboard
13
- */
14
- export async function setupHomarr(ctx: SetupContext): Promise<SetupResult> {
15
- const homarrConfig = getEnabledAppConfig(ctx, "homarr")
16
- if (!homarrConfig) {
17
- return { success: false, message: "Not enabled" }
18
- }
19
-
20
- const port = homarrConfig.port || 7575
21
- const client = new HomarrClient("localhost", port)
22
-
23
- try {
24
- const result = await client.setup({
25
- username: ctx.globalUsername,
26
- password: ctx.globalPassword,
27
- env: ctx.env,
28
- })
29
-
30
- if (result.success) {
31
- // Add enabled apps to Homarr dashboard
32
- try {
33
- const addedCount = await client.setupEasiarrApps(ctx.config.apps)
34
- return { ...result, message: `${result.message}, ${addedCount} apps added` }
35
- } catch {
36
- return result
37
- }
38
- } else {
39
- return result
40
- }
41
- } catch (e) {
42
- return { success: false, message: String(e) }
43
- }
44
- }
45
-
46
- /**
47
- * Setup Heimdall dashboard
48
- */
49
- export async function setupHeimdall(ctx: SetupContext): Promise<SetupResult> {
50
- const heimdallConfig = getEnabledAppConfig(ctx, "heimdall")
51
- if (!heimdallConfig) {
52
- return { success: false, message: "Not enabled" }
53
- }
54
-
55
- const port = heimdallConfig.port || 8090
56
- const client = new HeimdallClient("localhost", port)
57
-
58
- try {
59
- const result = await client.setup({
60
- username: ctx.globalUsername,
61
- password: ctx.globalPassword,
62
- env: ctx.env,
63
- })
64
-
65
- if (result.success) {
66
- // Add enabled apps to Heimdall dashboard
67
- try {
68
- const addedCount = await client.setupEasiarrApps(ctx.config.apps)
69
- return { ...result, message: `${result.message}, ${addedCount} apps added` }
70
- } catch {
71
- return result
72
- }
73
- } else {
74
- return result
75
- }
76
- } catch (e) {
77
- return { success: false, message: String(e) }
78
- }
79
- }
@@ -1,54 +0,0 @@
1
- /**
2
- * Download Client Setup Actions
3
- *
4
- * Setup functions for qBittorrent and other download clients.
5
- */
6
-
7
- import { QBittorrentCategory, QBittorrentClient } from "~/api/qbittorrent-api"
8
- import { getEnabledAppConfig, SetupContext, SetupResult } from "~/setup/types"
9
- import { getCategoriesForApps } from "~/utils/categories"
10
-
11
- /**
12
- * Setup qBittorrent with TRaSH-compliant settings
13
- */
14
- export async function setupQBittorrent(ctx: SetupContext): Promise<SetupResult> {
15
- const qbConfig = getEnabledAppConfig(ctx, "qbittorrent")
16
- if (!qbConfig) {
17
- return { success: false, message: "Not enabled" }
18
- }
19
-
20
- const host = "localhost"
21
- const port = qbConfig.port || 8080
22
- const user = ctx.env["USERNAME_QBITTORRENT"] || "admin"
23
- const pass = ctx.env["PASSWORD_QBITTORRENT"] || ctx.env["QBITTORRENT_PASS"] || ""
24
-
25
- if (!pass) {
26
- return { success: false, message: "No PASSWORD_QBITTORRENT in .env" }
27
- }
28
-
29
- const client = new QBittorrentClient(host, port, user, pass)
30
-
31
- try {
32
- const result = await client.setup({
33
- username: user,
34
- password: pass,
35
- env: ctx.env,
36
- })
37
-
38
- if (result.success) {
39
- // Configure categories after basic setup
40
- const enabledApps = ctx.config.apps.filter((a) => a.enabled).map((a) => a.id)
41
- const categories: QBittorrentCategory[] = getCategoriesForApps(enabledApps).map((cat) => ({
42
- name: cat.name,
43
- savePath: `/data/torrents/${cat.name}`,
44
- }))
45
-
46
- await client.configureTRaSHCompliant(categories, { user, pass })
47
- return { success: true, message: result.message }
48
- } else {
49
- return { success: false, message: result.message }
50
- }
51
- } catch (e) {
52
- return { success: false, message: String(e) }
53
- }
54
- }