@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
|
@@ -1,375 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Base App Setup Screen
|
|
3
|
-
*
|
|
4
|
-
* Abstract base class for all app setup screens.
|
|
5
|
-
* Provides common UI patterns: menu navigation, results display, key handling.
|
|
6
|
-
*
|
|
7
|
-
* Subclasses implement:
|
|
8
|
-
* - getTitle(): Screen title
|
|
9
|
-
* - getStepInfo(): Step info text
|
|
10
|
-
* - getMenuItems(): Menu items with actions
|
|
11
|
-
*
|
|
12
|
-
* @example
|
|
13
|
-
* ```ts
|
|
14
|
-
* export class JellyfinSetup extends BaseAppSetupScreen {
|
|
15
|
-
* getTitle() { return "Jellyfin Setup" }
|
|
16
|
-
* getStepInfo() { return "Configure Jellyfin" }
|
|
17
|
-
* getMenuItems() {
|
|
18
|
-
* return [
|
|
19
|
-
* { name: "🚀 Run Wizard", description: "...", action: () => this.runWizard() },
|
|
20
|
-
* { name: "↩️ Back", description: "Return", action: () => this.cleanup() },
|
|
21
|
-
* ]
|
|
22
|
-
* }
|
|
23
|
-
* }
|
|
24
|
-
* ```
|
|
25
|
-
*/
|
|
26
|
-
|
|
27
|
-
import { BoxRenderable, CliRenderer, KeyEvent, TextRenderable } from "@opentui/core"
|
|
28
|
-
|
|
29
|
-
import type { EasiarrConfig } from "~/config/schema"
|
|
30
|
-
import { createPageLayout } from "~/ui/components/PageLayout"
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Result of a setup step
|
|
34
|
-
*/
|
|
35
|
-
export interface SetupResult {
|
|
36
|
-
name: string
|
|
37
|
-
status: "pending" | "configuring" | "success" | "error" | "skipped"
|
|
38
|
-
message?: string
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Menu item definition
|
|
43
|
-
*/
|
|
44
|
-
export interface MenuItem {
|
|
45
|
-
name: string
|
|
46
|
-
description: string
|
|
47
|
-
action: () => void | Promise<void>
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Step state for the screen
|
|
52
|
-
*/
|
|
53
|
-
export type SetupStep = "menu" | "running" | "done"
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Footer hint item
|
|
57
|
-
*/
|
|
58
|
-
interface FooterHint {
|
|
59
|
-
type: "key"
|
|
60
|
-
key: string
|
|
61
|
-
value: string
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
export abstract class BaseAppSetupScreen extends BoxRenderable {
|
|
65
|
-
protected config: EasiarrConfig
|
|
66
|
-
protected cliRenderer: CliRenderer
|
|
67
|
-
protected onBack: () => void
|
|
68
|
-
protected keyHandler!: (key: KeyEvent) => void
|
|
69
|
-
protected contentBox!: BoxRenderable
|
|
70
|
-
protected pageContainer!: BoxRenderable
|
|
71
|
-
|
|
72
|
-
protected results: SetupResult[] = []
|
|
73
|
-
protected currentStep: SetupStep = "menu"
|
|
74
|
-
protected menuIndex = 0
|
|
75
|
-
|
|
76
|
-
constructor(cliRenderer: CliRenderer, config: EasiarrConfig, onBack: () => void) {
|
|
77
|
-
super(cliRenderer, { width: "100%", height: "100%" })
|
|
78
|
-
|
|
79
|
-
this.config = config
|
|
80
|
-
this.cliRenderer = cliRenderer
|
|
81
|
-
this.onBack = onBack
|
|
82
|
-
|
|
83
|
-
// Create layout with values from subclass (works because JS allows calling
|
|
84
|
-
// overridden methods from constructor, though TypeScript warns about it)
|
|
85
|
-
const layout = createPageLayout(cliRenderer, {
|
|
86
|
-
title: this.getTitle(),
|
|
87
|
-
stepInfo: this.getStepInfo(),
|
|
88
|
-
footerHint: this.getFooterHint(),
|
|
89
|
-
})
|
|
90
|
-
this.pageContainer = layout.container
|
|
91
|
-
this.contentBox = layout.content
|
|
92
|
-
this.add(this.pageContainer)
|
|
93
|
-
|
|
94
|
-
this.initKeyHandler()
|
|
95
|
-
this.refreshContent()
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
// ============================================
|
|
99
|
-
// ABSTRACT METHODS - Subclasses must implement
|
|
100
|
-
// ============================================
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* Screen title shown in header
|
|
104
|
-
*/
|
|
105
|
-
abstract getTitle(): string
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* Step info text shown below title
|
|
109
|
-
*/
|
|
110
|
-
abstract getStepInfo(): string
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* Menu items to display
|
|
114
|
-
*/
|
|
115
|
-
abstract getMenuItems(): MenuItem[]
|
|
116
|
-
|
|
117
|
-
// ============================================
|
|
118
|
-
// OPTIONAL OVERRIDES
|
|
119
|
-
// ============================================
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* Footer hints. Override to customize.
|
|
123
|
-
*/
|
|
124
|
-
protected getFooterHint(): FooterHint[] {
|
|
125
|
-
return [
|
|
126
|
-
{ type: "key", key: "↑↓", value: "Navigate" },
|
|
127
|
-
{ type: "key", key: "Enter", value: "Select" },
|
|
128
|
-
{ type: "key", key: "Esc", value: "Back" },
|
|
129
|
-
]
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* Custom content rendering. Override to add custom steps.
|
|
134
|
-
* Return false to use default rendering, true if handled.
|
|
135
|
-
*/
|
|
136
|
-
protected renderCustomContent(): boolean {
|
|
137
|
-
return false
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* Handle custom key events. Override to add custom key handling.
|
|
142
|
-
* Return true if handled, false to continue default handling.
|
|
143
|
-
*/
|
|
144
|
-
protected handleCustomKeys(_key: KeyEvent): boolean {
|
|
145
|
-
return false
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
// ============================================
|
|
149
|
-
// COMMON IMPLEMENTATION
|
|
150
|
-
// ============================================
|
|
151
|
-
|
|
152
|
-
protected initKeyHandler(): void {
|
|
153
|
-
this.keyHandler = (key: KeyEvent) => {
|
|
154
|
-
// Allow subclass to handle first
|
|
155
|
-
if (this.handleCustomKeys(key)) {
|
|
156
|
-
return
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
// Escape always goes back
|
|
160
|
-
if (key.name === "escape" || (key.name === "c" && key.ctrl)) {
|
|
161
|
-
if (this.currentStep === "menu") {
|
|
162
|
-
this.cleanup()
|
|
163
|
-
} else {
|
|
164
|
-
this.currentStep = "menu"
|
|
165
|
-
this.refreshContent()
|
|
166
|
-
}
|
|
167
|
-
return
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
// Handle based on current step
|
|
171
|
-
if (this.currentStep === "menu") {
|
|
172
|
-
this.handleMenuKeys(key)
|
|
173
|
-
} else if (this.currentStep === "done") {
|
|
174
|
-
if (key.name === "return" || key.name === "escape") {
|
|
175
|
-
this.currentStep = "menu"
|
|
176
|
-
this.refreshContent()
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
this.cliRenderer.keyInput.on("keypress", this.keyHandler)
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
protected handleMenuKeys(key: KeyEvent): void {
|
|
184
|
-
const menuItems = this.getMenuItems()
|
|
185
|
-
|
|
186
|
-
if (key.name === "up" && this.menuIndex > 0) {
|
|
187
|
-
this.menuIndex--
|
|
188
|
-
this.refreshContent()
|
|
189
|
-
} else if (key.name === "down" && this.menuIndex < menuItems.length - 1) {
|
|
190
|
-
this.menuIndex++
|
|
191
|
-
this.refreshContent()
|
|
192
|
-
} else if (key.name === "return") {
|
|
193
|
-
this.executeMenuItem(this.menuIndex)
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
protected executeMenuItem(index: number): void {
|
|
198
|
-
const items = this.getMenuItems()
|
|
199
|
-
if (index >= 0 && index < items.length) {
|
|
200
|
-
items[index].action()
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
protected refreshContent(): void {
|
|
205
|
-
this.contentBox.getChildren().forEach((child) => child.destroy())
|
|
206
|
-
|
|
207
|
-
// Allow subclass custom rendering
|
|
208
|
-
if (this.renderCustomContent()) {
|
|
209
|
-
return
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
// Default rendering
|
|
213
|
-
if (this.currentStep === "menu") {
|
|
214
|
-
this.renderMenu()
|
|
215
|
-
} else {
|
|
216
|
-
this.renderResults()
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
protected renderMenu(): void {
|
|
221
|
-
this.contentBox.add(
|
|
222
|
-
new TextRenderable(this.cliRenderer, {
|
|
223
|
-
content: this.getMenuDescription() + "\n\n",
|
|
224
|
-
fg: "#aaaaaa",
|
|
225
|
-
})
|
|
226
|
-
)
|
|
227
|
-
|
|
228
|
-
this.getMenuItems().forEach((item, idx) => {
|
|
229
|
-
const pointer = idx === this.menuIndex ? "→ " : " "
|
|
230
|
-
const fg = idx === this.menuIndex ? "#50fa7b" : "#8be9fd"
|
|
231
|
-
|
|
232
|
-
this.contentBox.add(
|
|
233
|
-
new TextRenderable(this.cliRenderer, {
|
|
234
|
-
content: `${pointer}${item.name}\n`,
|
|
235
|
-
fg,
|
|
236
|
-
})
|
|
237
|
-
)
|
|
238
|
-
this.contentBox.add(
|
|
239
|
-
new TextRenderable(this.cliRenderer, {
|
|
240
|
-
content: ` ${item.description}\n\n`,
|
|
241
|
-
fg: "#6272a4",
|
|
242
|
-
})
|
|
243
|
-
)
|
|
244
|
-
})
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
/**
|
|
248
|
-
* Description shown above menu. Override to customize.
|
|
249
|
-
*/
|
|
250
|
-
protected getMenuDescription(): string {
|
|
251
|
-
return "Select an option:"
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
protected renderResults(): void {
|
|
255
|
-
const headerText = this.currentStep === "done" ? "Results:\n\n" : "Configuring...\n\n"
|
|
256
|
-
this.contentBox.add(
|
|
257
|
-
new TextRenderable(this.cliRenderer, {
|
|
258
|
-
content: headerText,
|
|
259
|
-
fg: this.currentStep === "done" ? "#50fa7b" : "#f1fa8c",
|
|
260
|
-
})
|
|
261
|
-
)
|
|
262
|
-
|
|
263
|
-
for (const result of this.results) {
|
|
264
|
-
let status = ""
|
|
265
|
-
let fg = "#aaaaaa"
|
|
266
|
-
switch (result.status) {
|
|
267
|
-
case "pending":
|
|
268
|
-
status = "⏳"
|
|
269
|
-
break
|
|
270
|
-
case "configuring":
|
|
271
|
-
status = "🔄"
|
|
272
|
-
fg = "#f1fa8c"
|
|
273
|
-
break
|
|
274
|
-
case "success":
|
|
275
|
-
status = "✓"
|
|
276
|
-
fg = "#50fa7b"
|
|
277
|
-
break
|
|
278
|
-
case "error":
|
|
279
|
-
status = "✗"
|
|
280
|
-
fg = "#ff5555"
|
|
281
|
-
break
|
|
282
|
-
case "skipped":
|
|
283
|
-
status = "⊘"
|
|
284
|
-
fg = "#6272a4"
|
|
285
|
-
break
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
let content = `${status} ${result.name}`
|
|
289
|
-
if (result.message) {
|
|
290
|
-
content += ` - ${result.message}`
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
this.contentBox.add(new TextRenderable(this.cliRenderer, { content: content + "\n", fg }))
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
if (this.currentStep === "done") {
|
|
297
|
-
this.contentBox.add(
|
|
298
|
-
new TextRenderable(this.cliRenderer, {
|
|
299
|
-
content: "\nPress Enter or Esc to continue...",
|
|
300
|
-
fg: "#6272a4",
|
|
301
|
-
})
|
|
302
|
-
)
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
/**
|
|
307
|
-
* Helper to run an action and display result
|
|
308
|
-
*/
|
|
309
|
-
protected async runAction(
|
|
310
|
-
name: string,
|
|
311
|
-
action: () => Promise<{ success: boolean; message?: string }>
|
|
312
|
-
): Promise<void> {
|
|
313
|
-
this.currentStep = "running"
|
|
314
|
-
this.results = [{ name, status: "configuring" }]
|
|
315
|
-
this.refreshContent()
|
|
316
|
-
|
|
317
|
-
try {
|
|
318
|
-
const result = await action()
|
|
319
|
-
this.results[0] = {
|
|
320
|
-
name,
|
|
321
|
-
status: result.success ? "success" : "error",
|
|
322
|
-
message: result.message,
|
|
323
|
-
}
|
|
324
|
-
} catch (error) {
|
|
325
|
-
this.results[0] = {
|
|
326
|
-
name,
|
|
327
|
-
status: "error",
|
|
328
|
-
message: error instanceof Error ? error.message : String(error),
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
this.currentStep = "done"
|
|
333
|
-
this.refreshContent()
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
/**
|
|
337
|
-
* Helper to run multiple actions in sequence
|
|
338
|
-
*/
|
|
339
|
-
protected async runActions(
|
|
340
|
-
actions: Array<{ name: string; action: () => Promise<{ success: boolean; message?: string }> }>
|
|
341
|
-
): Promise<void> {
|
|
342
|
-
this.currentStep = "running"
|
|
343
|
-
this.results = actions.map((a) => ({ name: a.name, status: "pending" as const }))
|
|
344
|
-
this.refreshContent()
|
|
345
|
-
|
|
346
|
-
for (let i = 0; i < actions.length; i++) {
|
|
347
|
-
this.results[i].status = "configuring"
|
|
348
|
-
this.refreshContent()
|
|
349
|
-
|
|
350
|
-
try {
|
|
351
|
-
const result = await actions[i].action()
|
|
352
|
-
this.results[i] = {
|
|
353
|
-
name: actions[i].name,
|
|
354
|
-
status: result.success ? "success" : "error",
|
|
355
|
-
message: result.message,
|
|
356
|
-
}
|
|
357
|
-
} catch (error) {
|
|
358
|
-
this.results[i] = {
|
|
359
|
-
name: actions[i].name,
|
|
360
|
-
status: "error",
|
|
361
|
-
message: error instanceof Error ? error.message : String(error),
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
this.currentStep = "done"
|
|
367
|
-
this.refreshContent()
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
protected cleanup(): void {
|
|
371
|
-
this.cliRenderer.keyInput.off("keypress", this.keyHandler)
|
|
372
|
-
this.destroy()
|
|
373
|
-
this.onBack()
|
|
374
|
-
}
|
|
375
|
-
}
|