@muhammedaksam/easiarr 0.8.2 → 0.8.4
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/package.json +1 -1
- package/src/api/jellyfin-api.ts +48 -6
- package/src/api/jellyseerr-api.ts +538 -0
- package/src/apps/registry.ts +1 -0
- package/src/ui/screens/FullAutoSetup.ts +104 -0
- package/src/ui/screens/JellyseerrSetup.ts +612 -0
- package/src/ui/screens/MainMenu.ts +129 -173
|
@@ -18,6 +18,11 @@ import { FullAutoSetup } from "./FullAutoSetup"
|
|
|
18
18
|
import { MonitorDashboard } from "./MonitorDashboard"
|
|
19
19
|
import { HomepageSetup } from "./HomepageSetup"
|
|
20
20
|
import { JellyfinSetup } from "./JellyfinSetup"
|
|
21
|
+
import { JellyseerrSetup } from "./JellyseerrSetup"
|
|
22
|
+
|
|
23
|
+
type MenuItem = { name: string; description: string; action: () => void | Promise<void> }
|
|
24
|
+
|
|
25
|
+
type ScreenConstructor = new (renderer: CliRenderer, config: EasiarrConfig, onBack: () => void) => BoxRenderable
|
|
21
26
|
|
|
22
27
|
export class MainMenu {
|
|
23
28
|
private renderer: RenderContext
|
|
@@ -26,6 +31,7 @@ export class MainMenu {
|
|
|
26
31
|
private config: EasiarrConfig
|
|
27
32
|
private menu!: SelectRenderable
|
|
28
33
|
private page!: BoxRenderable
|
|
34
|
+
private menuItems: MenuItem[] = []
|
|
29
35
|
|
|
30
36
|
constructor(renderer: RenderContext, container: BoxRenderable, app: App, config: EasiarrConfig) {
|
|
31
37
|
this.renderer = renderer
|
|
@@ -36,6 +42,122 @@ export class MainMenu {
|
|
|
36
42
|
this.render()
|
|
37
43
|
}
|
|
38
44
|
|
|
45
|
+
private isAppEnabled(id: string): boolean {
|
|
46
|
+
return this.config.apps.some((a) => a.id === id && a.enabled)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
private buildMenuItems(): MenuItem[] {
|
|
50
|
+
const items: MenuItem[] = []
|
|
51
|
+
|
|
52
|
+
// Core items (always shown)
|
|
53
|
+
items.push({
|
|
54
|
+
name: "📦 Manage Apps",
|
|
55
|
+
description: "Add, remove, or configure apps",
|
|
56
|
+
action: () => this.app.navigateTo("appManager"),
|
|
57
|
+
})
|
|
58
|
+
items.push({
|
|
59
|
+
name: "🐳 Container Control",
|
|
60
|
+
description: "Start, stop, restart containers",
|
|
61
|
+
action: () => this.app.navigateTo("containerControl"),
|
|
62
|
+
})
|
|
63
|
+
items.push({
|
|
64
|
+
name: "⚙️ Advanced Settings",
|
|
65
|
+
description: "Customize ports, volumes, env",
|
|
66
|
+
action: () => this.app.navigateTo("advancedSettings"),
|
|
67
|
+
})
|
|
68
|
+
items.push({
|
|
69
|
+
name: "🔑 Extract API Keys",
|
|
70
|
+
description: "Find API keys from running containers",
|
|
71
|
+
action: () => this.showScreen(ApiKeyViewer),
|
|
72
|
+
})
|
|
73
|
+
items.push({
|
|
74
|
+
name: "⚙️ Configure Apps",
|
|
75
|
+
description: "Set root folders and download clients via API",
|
|
76
|
+
action: () => this.showScreen(AppConfigurator),
|
|
77
|
+
})
|
|
78
|
+
items.push({
|
|
79
|
+
name: "🎯 TRaSH Guide Setup",
|
|
80
|
+
description: "Apply TRaSH quality profiles and custom formats",
|
|
81
|
+
action: () => this.showScreen(TRaSHProfileSetup),
|
|
82
|
+
})
|
|
83
|
+
items.push({
|
|
84
|
+
name: "🔄 Regenerate Compose",
|
|
85
|
+
description: "Rebuild docker-compose.yml",
|
|
86
|
+
action: async () => {
|
|
87
|
+
await saveCompose(this.config)
|
|
88
|
+
},
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
// Conditional items based on enabled apps
|
|
92
|
+
if (this.isAppEnabled("prowlarr")) {
|
|
93
|
+
items.push({
|
|
94
|
+
name: "🔗 Prowlarr Setup",
|
|
95
|
+
description: "Sync indexers to *arr apps, FlareSolverr",
|
|
96
|
+
action: () => this.showScreen(ProwlarrSetup),
|
|
97
|
+
})
|
|
98
|
+
}
|
|
99
|
+
if (this.isAppEnabled("qbittorrent")) {
|
|
100
|
+
items.push({
|
|
101
|
+
name: "⚡ qBittorrent Setup",
|
|
102
|
+
description: "Configure TRaSH-compliant paths and categories",
|
|
103
|
+
action: () => this.showScreen(QBittorrentSetup),
|
|
104
|
+
})
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Full Auto Setup (always shown)
|
|
108
|
+
items.push({
|
|
109
|
+
name: "🚀 Full Auto Setup",
|
|
110
|
+
description: "Run all configurations (Auth, Root Folders, Prowlarr, etc.)",
|
|
111
|
+
action: () => this.showScreen(FullAutoSetup),
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
items.push({
|
|
115
|
+
name: "📊 Monitor Dashboard",
|
|
116
|
+
description: "Configure app health monitoring",
|
|
117
|
+
action: () => this.showScreen(MonitorDashboard),
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
if (this.isAppEnabled("homepage")) {
|
|
121
|
+
items.push({
|
|
122
|
+
name: "🏠 Homepage Setup",
|
|
123
|
+
description: "Generate Homepage dashboard config",
|
|
124
|
+
action: () => this.showScreen(HomepageSetup),
|
|
125
|
+
})
|
|
126
|
+
}
|
|
127
|
+
if (this.isAppEnabled("jellyfin")) {
|
|
128
|
+
items.push({
|
|
129
|
+
name: "🎬 Jellyfin Setup",
|
|
130
|
+
description: "Run Jellyfin setup wizard via API",
|
|
131
|
+
action: () => this.showScreen(JellyfinSetup),
|
|
132
|
+
})
|
|
133
|
+
}
|
|
134
|
+
if (this.isAppEnabled("jellyseerr")) {
|
|
135
|
+
items.push({
|
|
136
|
+
name: "🎥 Jellyseerr Setup",
|
|
137
|
+
description: "Configure Jellyseerr with media server",
|
|
138
|
+
action: () => this.showScreen(JellyseerrSetup),
|
|
139
|
+
})
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
items.push({
|
|
143
|
+
name: "❌ Exit",
|
|
144
|
+
description: "Close easiarr",
|
|
145
|
+
action: () => process.exit(0),
|
|
146
|
+
})
|
|
147
|
+
|
|
148
|
+
return items
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
private showScreen(ScreenClass: ScreenConstructor): void {
|
|
152
|
+
this.menu.blur()
|
|
153
|
+
this.page.visible = false
|
|
154
|
+
const screen = new ScreenClass(this.renderer as CliRenderer, this.config, () => {
|
|
155
|
+
this.page.visible = true
|
|
156
|
+
this.menu.focus()
|
|
157
|
+
})
|
|
158
|
+
this.container.add(screen)
|
|
159
|
+
}
|
|
160
|
+
|
|
39
161
|
private render(): void {
|
|
40
162
|
const { container: page, content } = createPageLayout(this.renderer as CliRenderer, {
|
|
41
163
|
title: "Main Menu",
|
|
@@ -81,187 +203,21 @@ export class MainMenu {
|
|
|
81
203
|
|
|
82
204
|
content.add(new TextRenderable(this.renderer, { id: "spacer2", content: " " }))
|
|
83
205
|
|
|
206
|
+
// Build menu items dynamically based on enabled apps
|
|
207
|
+
this.menuItems = this.buildMenuItems()
|
|
208
|
+
|
|
84
209
|
// Menu
|
|
85
210
|
this.menu = new SelectRenderable(this.renderer, {
|
|
86
211
|
id: "main-menu-select",
|
|
87
212
|
width: "100%",
|
|
88
213
|
flexGrow: 1,
|
|
89
|
-
options:
|
|
90
|
-
{
|
|
91
|
-
name: "📦 Manage Apps",
|
|
92
|
-
description: "Add, remove, or configure apps",
|
|
93
|
-
},
|
|
94
|
-
{
|
|
95
|
-
name: "🐳 Container Control",
|
|
96
|
-
description: "Start, stop, restart containers",
|
|
97
|
-
},
|
|
98
|
-
{
|
|
99
|
-
name: "⚙️ Advanced Settings",
|
|
100
|
-
description: "Customize ports, volumes, env",
|
|
101
|
-
},
|
|
102
|
-
{
|
|
103
|
-
name: "🔑 Extract API Keys",
|
|
104
|
-
description: "Find API keys from running containers",
|
|
105
|
-
},
|
|
106
|
-
{
|
|
107
|
-
name: "⚙️ Configure Apps",
|
|
108
|
-
description: "Set root folders and download clients via API",
|
|
109
|
-
},
|
|
110
|
-
{
|
|
111
|
-
name: "🎯 TRaSH Guide Setup",
|
|
112
|
-
description: "Apply TRaSH quality profiles and custom formats",
|
|
113
|
-
},
|
|
114
|
-
{
|
|
115
|
-
name: "🔄 Regenerate Compose",
|
|
116
|
-
description: "Rebuild docker-compose.yml",
|
|
117
|
-
},
|
|
118
|
-
{
|
|
119
|
-
name: "🔗 Prowlarr Setup",
|
|
120
|
-
description: "Sync indexers to *arr apps, FlareSolverr",
|
|
121
|
-
},
|
|
122
|
-
{
|
|
123
|
-
name: "⚡ qBittorrent Setup",
|
|
124
|
-
description: "Configure TRaSH-compliant paths and categories",
|
|
125
|
-
},
|
|
126
|
-
{
|
|
127
|
-
name: "🚀 Full Auto Setup",
|
|
128
|
-
description: "Run all configurations (Auth, Root Folders, Prowlarr, etc.)",
|
|
129
|
-
},
|
|
130
|
-
{
|
|
131
|
-
name: "📊 Monitor Dashboard",
|
|
132
|
-
description: "Configure app health monitoring",
|
|
133
|
-
},
|
|
134
|
-
{
|
|
135
|
-
name: "🏠 Homepage Setup",
|
|
136
|
-
description: "Generate Homepage dashboard config",
|
|
137
|
-
},
|
|
138
|
-
{
|
|
139
|
-
name: "🎬 Jellyfin Setup",
|
|
140
|
-
description: "Run Jellyfin setup wizard via API",
|
|
141
|
-
},
|
|
142
|
-
{ name: "❌ Exit", description: "Close easiarr" },
|
|
143
|
-
],
|
|
214
|
+
options: this.menuItems.map((item) => ({ name: item.name, description: item.description })),
|
|
144
215
|
})
|
|
145
216
|
|
|
146
217
|
this.menu.on(SelectRenderableEvents.ITEM_SELECTED, async (index) => {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
break
|
|
151
|
-
case 1:
|
|
152
|
-
this.app.navigateTo("containerControl")
|
|
153
|
-
break
|
|
154
|
-
case 2:
|
|
155
|
-
this.app.navigateTo("advancedSettings")
|
|
156
|
-
break
|
|
157
|
-
case 3: {
|
|
158
|
-
// API Key Extractor
|
|
159
|
-
this.menu.blur()
|
|
160
|
-
this.page.visible = false
|
|
161
|
-
const viewer = new ApiKeyViewer(this.renderer as CliRenderer, this.config, () => {
|
|
162
|
-
// On Back
|
|
163
|
-
this.page.visible = true
|
|
164
|
-
this.menu.focus()
|
|
165
|
-
})
|
|
166
|
-
this.container.add(viewer)
|
|
167
|
-
break
|
|
168
|
-
}
|
|
169
|
-
case 4: {
|
|
170
|
-
// Configure Apps
|
|
171
|
-
this.menu.blur()
|
|
172
|
-
this.page.visible = false
|
|
173
|
-
const configurator = new AppConfigurator(this.renderer as CliRenderer, this.config, () => {
|
|
174
|
-
this.page.visible = true
|
|
175
|
-
this.menu.focus()
|
|
176
|
-
})
|
|
177
|
-
this.container.add(configurator)
|
|
178
|
-
break
|
|
179
|
-
}
|
|
180
|
-
case 5: {
|
|
181
|
-
// TRaSH Profile Setup
|
|
182
|
-
this.menu.blur()
|
|
183
|
-
this.page.visible = false
|
|
184
|
-
const trashSetup = new TRaSHProfileSetup(this.renderer as CliRenderer, this.config, () => {
|
|
185
|
-
this.page.visible = true
|
|
186
|
-
this.menu.focus()
|
|
187
|
-
})
|
|
188
|
-
this.container.add(trashSetup)
|
|
189
|
-
break
|
|
190
|
-
}
|
|
191
|
-
case 6: {
|
|
192
|
-
// Regenerate compose
|
|
193
|
-
await saveCompose(this.config)
|
|
194
|
-
break
|
|
195
|
-
}
|
|
196
|
-
case 7: {
|
|
197
|
-
// Prowlarr Setup
|
|
198
|
-
this.menu.blur()
|
|
199
|
-
this.page.visible = false
|
|
200
|
-
const prowlarrSetup = new ProwlarrSetup(this.renderer as CliRenderer, this.config, () => {
|
|
201
|
-
this.page.visible = true
|
|
202
|
-
this.menu.focus()
|
|
203
|
-
})
|
|
204
|
-
this.container.add(prowlarrSetup)
|
|
205
|
-
break
|
|
206
|
-
}
|
|
207
|
-
case 8: {
|
|
208
|
-
// qBittorrent Setup
|
|
209
|
-
this.menu.blur()
|
|
210
|
-
this.page.visible = false
|
|
211
|
-
const qbSetup = new QBittorrentSetup(this.renderer as CliRenderer, this.config, () => {
|
|
212
|
-
this.page.visible = true
|
|
213
|
-
this.menu.focus()
|
|
214
|
-
})
|
|
215
|
-
this.container.add(qbSetup)
|
|
216
|
-
break
|
|
217
|
-
}
|
|
218
|
-
case 9: {
|
|
219
|
-
// Full Auto Setup
|
|
220
|
-
this.menu.blur()
|
|
221
|
-
this.page.visible = false
|
|
222
|
-
const autoSetup = new FullAutoSetup(this.renderer as CliRenderer, this.config, () => {
|
|
223
|
-
this.page.visible = true
|
|
224
|
-
this.menu.focus()
|
|
225
|
-
})
|
|
226
|
-
this.container.add(autoSetup)
|
|
227
|
-
break
|
|
228
|
-
}
|
|
229
|
-
case 10: {
|
|
230
|
-
// Monitor Dashboard
|
|
231
|
-
this.menu.blur()
|
|
232
|
-
this.page.visible = false
|
|
233
|
-
const monitor = new MonitorDashboard(this.renderer as CliRenderer, this.config, () => {
|
|
234
|
-
this.page.visible = true
|
|
235
|
-
this.menu.focus()
|
|
236
|
-
})
|
|
237
|
-
this.container.add(monitor)
|
|
238
|
-
break
|
|
239
|
-
}
|
|
240
|
-
case 11: {
|
|
241
|
-
// Homepage Setup
|
|
242
|
-
this.menu.blur()
|
|
243
|
-
this.page.visible = false
|
|
244
|
-
const homepageSetup = new HomepageSetup(this.renderer as CliRenderer, this.config, () => {
|
|
245
|
-
this.page.visible = true
|
|
246
|
-
this.menu.focus()
|
|
247
|
-
})
|
|
248
|
-
this.container.add(homepageSetup)
|
|
249
|
-
break
|
|
250
|
-
}
|
|
251
|
-
case 12: {
|
|
252
|
-
// Jellyfin Setup
|
|
253
|
-
this.menu.blur()
|
|
254
|
-
this.page.visible = false
|
|
255
|
-
const jellyfinSetup = new JellyfinSetup(this.renderer as CliRenderer, this.config, () => {
|
|
256
|
-
this.page.visible = true
|
|
257
|
-
this.menu.focus()
|
|
258
|
-
})
|
|
259
|
-
this.container.add(jellyfinSetup)
|
|
260
|
-
break
|
|
261
|
-
}
|
|
262
|
-
case 13:
|
|
263
|
-
process.exit(0)
|
|
264
|
-
break
|
|
218
|
+
const item = this.menuItems[index]
|
|
219
|
+
if (item) {
|
|
220
|
+
await item.action()
|
|
265
221
|
}
|
|
266
222
|
})
|
|
267
223
|
|