@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,391 +0,0 @@
1
- /**
2
- * Profilarr API Client
3
- * Handles authentication and *arr instance configuration
4
- */
5
-
6
- import type { AutoSetupOptions, AutoSetupResult, IAutoSetupClient } from "./auto-setup-types"
7
- import { debugLog } from "~/utils/debug"
8
-
9
- // ==========================================
10
- // Types
11
- // ==========================================
12
-
13
- export interface ProfilarrConfig {
14
- id?: number
15
- name: string
16
- type: "radarr" | "sonarr"
17
- tags: string[]
18
- arrServer: string
19
- apiKey: string
20
- sync_method: "manual" | "schedule"
21
- sync_interval: number
22
- import_as_unique: boolean
23
- data_to_sync: {
24
- profiles: string[]
25
- customFormats: string[]
26
- }
27
- }
28
-
29
- interface ProfilarrSetupStatus {
30
- needs_setup: boolean
31
- }
32
-
33
- interface ProfilarrSetupResponse {
34
- message: string
35
- username: string
36
- api_key: string
37
- authenticated: boolean
38
- }
39
-
40
- interface ProfilarrSettings {
41
- username: string
42
- api_key: string
43
- }
44
-
45
- interface ProfilarrApiResponse<T> {
46
- data: T
47
- success: boolean
48
- }
49
-
50
- // ==========================================
51
- // Client
52
- // ==========================================
53
-
54
- export class ProfilarrApiClient implements IAutoSetupClient {
55
- private baseUrl: string
56
- private apiKey: string | null = null
57
-
58
- constructor(host: string, port: number) {
59
- this.baseUrl = `http://${host}:${port}/api`
60
- }
61
-
62
- setApiKey(key: string): void {
63
- this.apiKey = key
64
- }
65
-
66
- private async request<T>(endpoint: string, options: RequestInit = {}): Promise<T> {
67
- const url = `${this.baseUrl}${endpoint}`
68
- const headers: Record<string, string> = {
69
- "Content-Type": "application/json",
70
- ...(this.apiKey ? { "X-Api-Key": this.apiKey } : {}),
71
- ...(options.headers as Record<string, string>),
72
- }
73
-
74
- debugLog("ProfilarrApi", `${options.method || "GET"} ${endpoint}`)
75
-
76
- const response = await fetch(url, { ...options, headers })
77
-
78
- if (!response.ok) {
79
- const text = await response.text()
80
- debugLog("ProfilarrApi", `Error ${response.status}: ${text}`)
81
- throw new Error(`Profilarr API error: ${response.status} - ${text}`)
82
- }
83
-
84
- const contentType = response.headers.get("content-type")
85
- if (contentType?.includes("application/json")) {
86
- return response.json()
87
- }
88
- return {} as T
89
- }
90
-
91
- // ==========================================
92
- // Health & Status
93
- // ==========================================
94
-
95
- async isHealthy(): Promise<boolean> {
96
- try {
97
- const response = await fetch(`${this.baseUrl}/auth/setup`)
98
- return response.status === 200 || response.status === 400
99
- } catch {
100
- return false
101
- }
102
- }
103
-
104
- async isInitialized(): Promise<boolean> {
105
- try {
106
- const response = await fetch(`${this.baseUrl}/auth/setup`)
107
- if (response.status === 400) return true // "Auth already configured"
108
- if (response.status === 200) {
109
- const data = (await response.json()) as ProfilarrSetupStatus
110
- return !data.needs_setup
111
- }
112
- return false
113
- } catch {
114
- return false
115
- }
116
- }
117
-
118
- // ==========================================
119
- // Authentication
120
- // ==========================================
121
-
122
- /**
123
- * Authenticate with Profilarr.
124
- * If not set up, performs initial setup.
125
- * If already configured, logs in and retrieves API key.
126
- */
127
- async authenticate(username: string, password: string): Promise<string> {
128
- // Check if setup is needed
129
- try {
130
- debugLog("ProfilarrApi", "Checking if setup is needed...")
131
- const response = await fetch(`${this.baseUrl}/auth/setup`)
132
- debugLog("ProfilarrApi", `Setup check status: ${response.status}`)
133
-
134
- if (response.status === 200) {
135
- const status = (await response.json()) as ProfilarrSetupStatus
136
- debugLog("ProfilarrApi", `Setup status: needs_setup=${status.needs_setup}`)
137
-
138
- if (status.needs_setup) {
139
- debugLog("ProfilarrApi", "Performing initial setup")
140
- const setupRes = await this.request<ProfilarrSetupResponse>("/auth/setup", {
141
- method: "POST",
142
- body: JSON.stringify({ username, password }),
143
- })
144
- debugLog("ProfilarrApi", `Setup successful, got API key`)
145
- this.apiKey = setupRes.api_key
146
- return this.apiKey
147
- }
148
- }
149
- } catch (e) {
150
- debugLog("ProfilarrApi", `Setup check/perform error: ${e}`)
151
- // Continue to try login
152
- }
153
-
154
- // Already configured, login to get API key
155
- debugLog("ProfilarrApi", "Logging in to retrieve API key")
156
- const loginRes = await fetch(`${this.baseUrl}/auth/authenticate`, {
157
- method: "POST",
158
- headers: { "Content-Type": "application/json" },
159
- body: JSON.stringify({ username, password }),
160
- })
161
-
162
- if (!loginRes.ok) {
163
- throw new Error(`Login failed: ${loginRes.statusText}`)
164
- }
165
-
166
- const cookie = loginRes.headers.get("set-cookie")
167
- if (!cookie) {
168
- throw new Error("Login successful but no cookie received")
169
- }
170
-
171
- // Get API key from settings using the cookie
172
- const settingsRes = await fetch(`${this.baseUrl}/settings/general`, {
173
- headers: { Cookie: cookie },
174
- })
175
-
176
- if (!settingsRes.ok) {
177
- throw new Error(`Failed to fetch settings: ${settingsRes.statusText}`)
178
- }
179
-
180
- const settings = (await settingsRes.json()) as ProfilarrSettings
181
- this.apiKey = settings.api_key
182
- return this.apiKey
183
- }
184
-
185
- // ==========================================
186
- // Arr Configuration
187
- // ==========================================
188
-
189
- async getConfigs(): Promise<ProfilarrConfig[]> {
190
- const response = await this.request<ProfilarrApiResponse<ProfilarrConfig[]>>("/arr/config")
191
- return response.data || []
192
- }
193
-
194
- async addConfig(config: ProfilarrConfig): Promise<ProfilarrConfig | null> {
195
- const response = await this.request<{ id?: number; success: boolean }>("/arr/config", {
196
- method: "POST",
197
- body: JSON.stringify(config),
198
- })
199
- if (response.success && response.id) {
200
- debugLog("ProfilarrApi", `Config created with id: ${response.id}`)
201
- return { ...config, id: response.id }
202
- }
203
- return null
204
- }
205
-
206
- /**
207
- * Configure Radarr connection
208
- * @returns The created/existing config, or null if failed
209
- */
210
- async configureRadarr(
211
- hostname: string,
212
- port: number,
213
- apiKey: string
214
- ): Promise<ProfilarrConfig | null> {
215
- try {
216
- const existingConfigs = await this.getConfigs()
217
- const existingConfig = existingConfigs.find((c) => c.type === "radarr")
218
-
219
- if (existingConfig) {
220
- debugLog("ProfilarrApi", "Radarr already configured")
221
- return existingConfig
222
- }
223
-
224
- const arrServer = `http://${hostname}:${port}`
225
- return await this.addConfig({
226
- name: "Radarr",
227
- type: "radarr",
228
- tags: [],
229
- arrServer,
230
- apiKey,
231
- sync_method: "manual",
232
- sync_interval: 60,
233
- import_as_unique: false,
234
- data_to_sync: { profiles: [], customFormats: [] },
235
- })
236
- } catch (e) {
237
- debugLog("ProfilarrApi", `Radarr config failed: ${e}`)
238
- return null
239
- }
240
- }
241
-
242
- /**
243
- * Configure Sonarr connection
244
- * @returns The created/existing config, or null if failed
245
- */
246
- async configureSonarr(
247
- hostname: string,
248
- port: number,
249
- apiKey: string
250
- ): Promise<ProfilarrConfig | null> {
251
- try {
252
- const existingConfigs = await this.getConfigs()
253
- const existingConfig = existingConfigs.find((c) => c.type === "sonarr")
254
-
255
- if (existingConfig) {
256
- debugLog("ProfilarrApi", "Sonarr already configured")
257
- return existingConfig
258
- }
259
-
260
- const arrServer = `http://${hostname}:${port}`
261
- return await this.addConfig({
262
- name: "Sonarr",
263
- type: "sonarr",
264
- tags: [],
265
- arrServer,
266
- apiKey,
267
- sync_method: "manual",
268
- sync_interval: 60,
269
- import_as_unique: false,
270
- data_to_sync: { profiles: [], customFormats: [] },
271
- })
272
- } catch (e) {
273
- debugLog("ProfilarrApi", `Sonarr config failed: ${e}`)
274
- return null
275
- }
276
- }
277
-
278
- // ==========================================
279
- // Git & Settings
280
- // ==========================================
281
-
282
- /**
283
- * Get current settings including git repo status
284
- */
285
- async getSettings(): Promise<{ gitRepo: string | null; auto_pull_enabled: string }> {
286
- return this.request<{ gitRepo: string | null; auto_pull_enabled: string }>("/settings")
287
- }
288
-
289
- /**
290
- * Clone the Dictionarry database repository
291
- * @returns true if cloned successfully or already cloned
292
- */
293
- async cloneDatabase(): Promise<boolean> {
294
- try {
295
- // Check if already cloned
296
- const settings = await this.getSettings()
297
- if (settings.gitRepo) {
298
- debugLog("ProfilarrApi", `Database already cloned: ${settings.gitRepo}`)
299
- return true
300
- }
301
-
302
- // Clone the Dictionarry database
303
- debugLog("ProfilarrApi", "Cloning Dictionarry database...")
304
- const response = await this.request<{ message: string }>("/git/clone", {
305
- method: "POST",
306
- body: JSON.stringify({ gitRepo: "https://github.com/Dictionarry-Hub/database" }),
307
- })
308
- debugLog("ProfilarrApi", `Clone result: ${response.message}`)
309
- return true
310
- } catch (e) {
311
- debugLog("ProfilarrApi", `Clone failed: ${e}`)
312
- return false
313
- }
314
- }
315
-
316
- /**
317
- * Sync a specific arr config
318
- * @param configId The config ID to sync
319
- */
320
- async syncConfig(configId: number): Promise<boolean> {
321
- try {
322
- debugLog("ProfilarrApi", `Syncing config ${configId}...`)
323
- const response = await this.request<{ success: boolean }>(`/arr/config/${configId}/sync`, {
324
- method: "POST",
325
- body: JSON.stringify({}),
326
- })
327
- debugLog(
328
- "ProfilarrApi",
329
- `Sync config ${configId}: ${response.success ? "success" : "failed"}`
330
- )
331
- return response.success
332
- } catch (e) {
333
- debugLog("ProfilarrApi", `Sync config ${configId} failed: ${e}`)
334
- return false
335
- }
336
- }
337
-
338
- /**
339
- * Sync all configured arr instances
340
- */
341
- async syncAllConfigs(): Promise<void> {
342
- try {
343
- const configs = await this.getConfigs()
344
- for (const config of configs) {
345
- if (config.id) {
346
- await this.syncConfig(config.id)
347
- }
348
- }
349
- } catch (e) {
350
- debugLog("ProfilarrApi", `Sync all failed: ${e}`)
351
- }
352
- }
353
-
354
- // ==========================================
355
- // Auto-Setup (IAutoSetupClient)
356
- // ==========================================
357
-
358
- /**
359
- * Run the auto-setup process for Profilarr.
360
- * Handles authentication, clones the Dictionarry database, and syncs to arr instances.
361
- */
362
- async setup(options: AutoSetupOptions): Promise<AutoSetupResult> {
363
- const { username, password } = options
364
-
365
- try {
366
- // Check if reachable
367
- const healthy = await this.isHealthy()
368
- if (!healthy) {
369
- return { success: false, message: "Profilarr not reachable" }
370
- }
371
-
372
- // Authenticate (setup or login)
373
- const apiKey = await this.authenticate(username, password)
374
-
375
- // Clone the Dictionarry database
376
- const cloned = await this.cloneDatabase()
377
- if (!cloned) {
378
- debugLog("ProfilarrApi", "Warning: Could not clone database, continuing anyway")
379
- }
380
-
381
- return {
382
- success: true,
383
- message: "Profilarr configured",
384
- data: { apiKey },
385
- envUpdates: { API_KEY_PROFILARR: apiKey },
386
- }
387
- } catch (error) {
388
- return { success: false, message: `${error}` }
389
- }
390
- }
391
- }