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