@muhammedaksam/easiarr 1.3.5 → 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/README.md +8 -5
- package/dist/index.js +29837 -0
- package/package.json +18 -16
- package/src/VersionInfo.ts +0 -12
- package/src/api/arr-api.ts +0 -508
- package/src/api/auto-setup-types.ts +0 -64
- package/src/api/bazarr-api.ts +0 -356
- package/src/api/cloudflare-api.ts +0 -577
- package/src/api/custom-format-api.ts +0 -212
- package/src/api/grafana-api.ts +0 -314
- package/src/api/heimdall-api.ts +0 -209
- package/src/api/homarr-api.ts +0 -296
- package/src/api/huntarr-api.ts +0 -622
- package/src/api/index.ts +0 -1
- package/src/api/jellyfin-api.ts +0 -473
- package/src/api/jellyseerr-api.ts +0 -660
- package/src/api/maintainerr-api.ts +0 -731
- package/src/api/naming-config.ts +0 -93
- package/src/api/overseerr-api.ts +0 -513
- package/src/api/plex-api.ts +0 -358
- package/src/api/portainer-api.ts +0 -467
- package/src/api/profilarr-api.ts +0 -380
- package/src/api/prowlarr-api.ts +0 -859
- package/src/api/qbittorrent-api.ts +0 -339
- package/src/api/quality-profile-api.ts +0 -269
- package/src/api/tautulli-api.ts +0 -277
- package/src/api/uptime-kuma-api.ts +0 -342
- package/src/apps/categories.ts +0 -14
- package/src/apps/index.ts +0 -2
- package/src/apps/registry.ts +0 -1255
- package/src/compose/caddy-config.ts +0 -129
- package/src/compose/generator.ts +0 -262
- package/src/compose/index.ts +0 -3
- package/src/compose/templates.ts +0 -78
- package/src/compose/traefik-config.ts +0 -185
- package/src/config/bookmarks-generator.ts +0 -149
- package/src/config/defaults.ts +0 -37
- package/src/config/homepage-config.ts +0 -376
- package/src/config/index.ts +0 -3
- package/src/config/manager.ts +0 -149
- package/src/config/recyclarr-config.ts +0 -179
- package/src/config/schema.ts +0 -310
- package/src/config/slskd-config.ts +0 -85
- 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 -326
- package/src/docker/client.ts +0 -291
- package/src/docker/index.ts +0 -1
- package/src/index.ts +0 -77
- package/src/structure/manager.ts +0 -128
- package/src/ui/App.ts +0 -109
- package/src/ui/components/ApplicationSelector.ts +0 -272
- package/src/ui/components/FileEditor.ts +0 -91
- package/src/ui/components/FooterHint.ts +0 -119
- package/src/ui/components/PageLayout.ts +0 -152
- package/src/ui/components/UpdateNotification.ts +0 -101
- package/src/ui/index.ts +0 -1
- package/src/ui/screens/AdvancedSettings.ts +0 -181
- package/src/ui/screens/ApiKeyViewer.ts +0 -500
- package/src/ui/screens/AppConfigurator.ts +0 -731
- package/src/ui/screens/AppManager.ts +0 -276
- package/src/ui/screens/CloudflaredSetup.ts +0 -974
- package/src/ui/screens/ContainerControl.ts +0 -579
- package/src/ui/screens/FullAutoSetup.ts +0 -1719
- package/src/ui/screens/HomepageSetup.ts +0 -306
- package/src/ui/screens/JellyfinSetup.ts +0 -471
- package/src/ui/screens/JellyseerrSetup.ts +0 -612
- package/src/ui/screens/LogsViewer.ts +0 -468
- package/src/ui/screens/MainMenu.ts +0 -288
- package/src/ui/screens/MonitorDashboard.ts +0 -866
- package/src/ui/screens/ProwlarrSetup.ts +0 -623
- package/src/ui/screens/QBittorrentSetup.ts +0 -268
- package/src/ui/screens/QuickSetup.ts +0 -1161
- package/src/ui/screens/RecyclarrSetup.ts +0 -418
- package/src/ui/screens/SecretsEditor.ts +0 -214
- package/src/ui/screens/SettingsScreen.ts +0 -605
- package/src/ui/screens/TRaSHProfileSetup.ts +0 -395
- package/src/ui/screens/index.ts +0 -4
- package/src/util/arch.ts +0 -78
- package/src/utils/browser.ts +0 -26
- package/src/utils/categories.ts +0 -59
- package/src/utils/debug.ts +0 -91
- package/src/utils/env.ts +0 -137
- package/src/utils/logs.ts +0 -118
- package/src/utils/migrations/1765626338_rename_env_variables.ts +0 -101
- package/src/utils/migrations/1765707135_rename_easiarr_status.ts +0 -90
- package/src/utils/migrations/1765732722_remove_cloudflare_dns_api_token.ts +0 -44
- package/src/utils/migrations/1769515650_migrate_to_xdg.ts +0 -107
- package/src/utils/migrations.ts +0 -164
- package/src/utils/password.ts +0 -42
- package/src/utils/unraid.ts +0 -101
- package/src/utils/update-checker.ts +0 -210
- package/src/utils/url-utils.ts +0 -38
package/src/api/bazarr-api.ts
DELETED
|
@@ -1,356 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Bazarr API Client
|
|
3
|
-
* Handles Bazarr-specific API calls for authentication and settings
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { debugLog } from "../utils/debug"
|
|
7
|
-
import type { IAutoSetupClient, AutoSetupOptions, AutoSetupResult } from "./auto-setup-types"
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Bazarr Language Profile Structure
|
|
11
|
-
*/
|
|
12
|
-
export interface BazarrLanguageProfile {
|
|
13
|
-
name: string
|
|
14
|
-
cutoff: string
|
|
15
|
-
languages: {
|
|
16
|
-
code: string
|
|
17
|
-
forced: boolean
|
|
18
|
-
hi: boolean
|
|
19
|
-
}[]
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Bazarr System Settings (partial - auth related fields)
|
|
24
|
-
*/
|
|
25
|
-
export interface BazarrAuthSettings {
|
|
26
|
-
auth: {
|
|
27
|
-
type: "None" | "Basic" | "Form"
|
|
28
|
-
username: string
|
|
29
|
-
password: string
|
|
30
|
-
apikey: string
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Bazarr API Client
|
|
36
|
-
* Note: Bazarr uses form data for POST, not JSON!
|
|
37
|
-
*/
|
|
38
|
-
export class BazarrApiClient implements IAutoSetupClient {
|
|
39
|
-
private baseUrl: string
|
|
40
|
-
private apiKey: string | null = null
|
|
41
|
-
|
|
42
|
-
constructor(host: string, port: number) {
|
|
43
|
-
this.baseUrl = `http://${host}:${port}`
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Set API key for authentication
|
|
48
|
-
*/
|
|
49
|
-
setApiKey(key: string): void {
|
|
50
|
-
this.apiKey = key
|
|
51
|
-
debugLog("Bazarr", `API key set`)
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Make a GET request to Bazarr API (JSON response)
|
|
56
|
-
*/
|
|
57
|
-
private async get<T>(endpoint: string): Promise<T> {
|
|
58
|
-
let url = `${this.baseUrl}/api${endpoint}`
|
|
59
|
-
if (this.apiKey) {
|
|
60
|
-
url = `${url}${url.includes("?") ? "&" : "?"}apikey=${this.apiKey}`
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
debugLog("Bazarr", `GET ${url}`)
|
|
64
|
-
|
|
65
|
-
const response = await fetch(url, {
|
|
66
|
-
method: "GET",
|
|
67
|
-
headers: {
|
|
68
|
-
Accept: "application/json",
|
|
69
|
-
},
|
|
70
|
-
})
|
|
71
|
-
|
|
72
|
-
if (!response.ok) {
|
|
73
|
-
const errorText = await response.text()
|
|
74
|
-
debugLog("Bazarr", `Error ${response.status}: ${errorText}`)
|
|
75
|
-
throw new Error(`Bazarr API error: ${response.status} ${response.statusText}`)
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
const text = await response.text()
|
|
79
|
-
debugLog("Bazarr", `Response: ${text.substring(0, 200)}${text.length > 200 ? "..." : ""}`)
|
|
80
|
-
if (!text) return {} as T
|
|
81
|
-
|
|
82
|
-
return JSON.parse(text) as T
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Make a POST request to Bazarr API using form data (NOT JSON)
|
|
87
|
-
* Bazarr uses request.form, not request.json
|
|
88
|
-
*/
|
|
89
|
-
private async postForm(endpoint: string, data: Record<string, string>): Promise<void> {
|
|
90
|
-
let url = `${this.baseUrl}/api${endpoint}`
|
|
91
|
-
if (this.apiKey) {
|
|
92
|
-
url = `${url}${url.includes("?") ? "&" : "?"}apikey=${this.apiKey}`
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// Convert object to form data
|
|
96
|
-
const formData = new URLSearchParams()
|
|
97
|
-
for (const [key, value] of Object.entries(data)) {
|
|
98
|
-
formData.append(key, value)
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
debugLog("Bazarr", `POST ${url}`)
|
|
102
|
-
debugLog("Bazarr", `Form data: ${formData.toString()}`)
|
|
103
|
-
|
|
104
|
-
const response = await fetch(url, {
|
|
105
|
-
method: "POST",
|
|
106
|
-
headers: {
|
|
107
|
-
"Content-Type": "application/x-www-form-urlencoded",
|
|
108
|
-
},
|
|
109
|
-
body: formData.toString(),
|
|
110
|
-
})
|
|
111
|
-
|
|
112
|
-
if (!response.ok) {
|
|
113
|
-
const errorText = await response.text()
|
|
114
|
-
debugLog("Bazarr", `Error ${response.status}: ${errorText}`)
|
|
115
|
-
throw new Error(`Bazarr API error: ${response.status} ${response.statusText}`)
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
debugLog("Bazarr", `Response status: ${response.status}`)
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* Check if Bazarr is healthy and reachable
|
|
123
|
-
*/
|
|
124
|
-
async isHealthy(): Promise<boolean> {
|
|
125
|
-
try {
|
|
126
|
-
await this.get("/system/status")
|
|
127
|
-
return true
|
|
128
|
-
} catch {
|
|
129
|
-
return false
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
* Get current system settings
|
|
135
|
-
*/
|
|
136
|
-
async getSettings(): Promise<Record<string, unknown>> {
|
|
137
|
-
return this.get<Record<string, unknown>>("/system/settings")
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* Update authentication settings to enable form-based auth
|
|
142
|
-
* Bazarr settings use dot notation in form fields
|
|
143
|
-
*/
|
|
144
|
-
async enableFormAuth(username: string, password: string, override = false): Promise<boolean> {
|
|
145
|
-
try {
|
|
146
|
-
// First get current settings to check if auth is already configured
|
|
147
|
-
const currentSettings = await this.getSettings()
|
|
148
|
-
const currentAuth = (currentSettings as { auth?: { type?: string } }).auth
|
|
149
|
-
|
|
150
|
-
// Skip if auth is already configured and override is false
|
|
151
|
-
if (currentAuth?.type && currentAuth.type !== "None" && currentAuth.type !== null && !override) {
|
|
152
|
-
debugLog("Bazarr", `Auth already configured (type: ${currentAuth.type}), skipping`)
|
|
153
|
-
return false
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
debugLog("Bazarr", `Current auth type: ${currentAuth?.type || "None"}`)
|
|
157
|
-
debugLog("Bazarr", `Setting form auth for user: ${username}`)
|
|
158
|
-
|
|
159
|
-
// Bazarr uses dot notation for nested settings in form data
|
|
160
|
-
await this.postForm("/system/settings", {
|
|
161
|
-
"settings-auth-type": "form",
|
|
162
|
-
"settings-auth-username": username,
|
|
163
|
-
"settings-auth-password": password,
|
|
164
|
-
})
|
|
165
|
-
|
|
166
|
-
debugLog("Bazarr", `Form auth enabled for user: ${username}`)
|
|
167
|
-
return true
|
|
168
|
-
} catch (e) {
|
|
169
|
-
debugLog("Bazarr", `Failed to enable form auth: ${e}`)
|
|
170
|
-
throw e
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
/**
|
|
175
|
-
* Get API key from settings
|
|
176
|
-
*/
|
|
177
|
-
async getApiKey(): Promise<string | null> {
|
|
178
|
-
try {
|
|
179
|
-
const settings = await this.getSettings()
|
|
180
|
-
const auth = (settings as unknown as BazarrAuthSettings).auth
|
|
181
|
-
return auth?.apikey || null
|
|
182
|
-
} catch {
|
|
183
|
-
return null
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
/**
|
|
188
|
-
* Configure Radarr connection in Bazarr
|
|
189
|
-
*/
|
|
190
|
-
async configureRadarr(host: string, port: number, apiKey: string): Promise<boolean> {
|
|
191
|
-
try {
|
|
192
|
-
debugLog("Bazarr", `Configuring Radarr connection: ${host}:${port}`)
|
|
193
|
-
|
|
194
|
-
await this.postForm("/system/settings", {
|
|
195
|
-
"settings-radarr-ip": host,
|
|
196
|
-
"settings-radarr-port": String(port),
|
|
197
|
-
"settings-radarr-apikey": apiKey,
|
|
198
|
-
"settings-radarr-base_url": "",
|
|
199
|
-
"settings-radarr-ssl": "false",
|
|
200
|
-
"settings-general-use_radarr": "true",
|
|
201
|
-
})
|
|
202
|
-
|
|
203
|
-
debugLog("Bazarr", "Radarr connection configured successfully")
|
|
204
|
-
return true
|
|
205
|
-
} catch (e) {
|
|
206
|
-
debugLog("Bazarr", `Failed to configure Radarr: ${e}`)
|
|
207
|
-
throw e
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
/**
|
|
212
|
-
* Configure Sonarr connection in Bazarr
|
|
213
|
-
*/
|
|
214
|
-
async configureSonarr(host: string, port: number, apiKey: string): Promise<boolean> {
|
|
215
|
-
try {
|
|
216
|
-
debugLog("Bazarr", `Configuring Sonarr connection: ${host}:${port}`)
|
|
217
|
-
|
|
218
|
-
await this.postForm("/system/settings", {
|
|
219
|
-
"settings-sonarr-ip": host,
|
|
220
|
-
"settings-sonarr-port": String(port),
|
|
221
|
-
"settings-sonarr-apikey": apiKey,
|
|
222
|
-
"settings-sonarr-base_url": "",
|
|
223
|
-
"settings-sonarr-ssl": "false",
|
|
224
|
-
"settings-general-use_sonarr": "true",
|
|
225
|
-
})
|
|
226
|
-
|
|
227
|
-
debugLog("Bazarr", "Sonarr connection configured successfully")
|
|
228
|
-
return true
|
|
229
|
-
} catch (e) {
|
|
230
|
-
debugLog("Bazarr", `Failed to configure Sonarr: ${e}`)
|
|
231
|
-
throw e
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
/**
|
|
236
|
-
* Check if already configured (has auth set up)
|
|
237
|
-
*/
|
|
238
|
-
async isInitialized(): Promise<boolean> {
|
|
239
|
-
try {
|
|
240
|
-
const settings = await this.getSettings()
|
|
241
|
-
const auth = (settings as { auth?: { type?: string } }).auth
|
|
242
|
-
return !!auth?.type && auth.type !== "None"
|
|
243
|
-
} catch {
|
|
244
|
-
return false
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
/**
|
|
249
|
-
* Configure General Settings (TRaSH Recommended)
|
|
250
|
-
*/
|
|
251
|
-
async configureGeneralSettings(): Promise<boolean> {
|
|
252
|
-
try {
|
|
253
|
-
debugLog("Bazarr", "Configuring general settings")
|
|
254
|
-
await this.postForm("/system/settings", {
|
|
255
|
-
"settings-subtitles-use_embedded_subtitles": "true",
|
|
256
|
-
"settings-subtitles-autosearch": "true",
|
|
257
|
-
"settings-subtitles-path_mapping": "", // Empty = Alongside Media File
|
|
258
|
-
})
|
|
259
|
-
return true
|
|
260
|
-
} catch (e) {
|
|
261
|
-
debugLog("Bazarr", `Failed to configure general settings: ${e}`)
|
|
262
|
-
return false
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
/**
|
|
267
|
-
* Get all language profiles
|
|
268
|
-
*/
|
|
269
|
-
async getLanguageProfiles(): Promise<BazarrLanguageProfile[]> {
|
|
270
|
-
return this.get<BazarrLanguageProfile[]>("/system/languages/profiles")
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
/**
|
|
274
|
-
* Configure Default Language Profile
|
|
275
|
-
* Creates an english profile if it doesn't exist
|
|
276
|
-
*/
|
|
277
|
-
async configureDefaultLanguageProfile(name = "English", language = "en"): Promise<boolean> {
|
|
278
|
-
try {
|
|
279
|
-
debugLog("Bazarr", `Configuring language profile: ${name}`)
|
|
280
|
-
|
|
281
|
-
// Get existing profiles to check and to preserve them
|
|
282
|
-
const profiles = (await this.getLanguageProfiles()) || []
|
|
283
|
-
const existing = profiles.find((p) => p.name === name)
|
|
284
|
-
|
|
285
|
-
if (existing) {
|
|
286
|
-
debugLog("Bazarr", `Language profile '${name}' already exists`)
|
|
287
|
-
return true
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
const newProfile: BazarrLanguageProfile = {
|
|
291
|
-
name: name,
|
|
292
|
-
cutoff: language,
|
|
293
|
-
languages: [
|
|
294
|
-
{
|
|
295
|
-
code: language,
|
|
296
|
-
forced: false,
|
|
297
|
-
hi: false,
|
|
298
|
-
},
|
|
299
|
-
],
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
profiles.push(newProfile)
|
|
303
|
-
|
|
304
|
-
// Update settings with the new list (serialized as JSON)
|
|
305
|
-
// Note: Bazarr expects 'languages_profiles' as a JSON string in the form data
|
|
306
|
-
await this.postForm("/system/settings", {
|
|
307
|
-
languages_profiles: JSON.stringify(profiles),
|
|
308
|
-
})
|
|
309
|
-
|
|
310
|
-
debugLog("Bazarr", `Created language profile: ${name}`)
|
|
311
|
-
return true
|
|
312
|
-
} catch (e) {
|
|
313
|
-
debugLog("Bazarr", `Failed to configure language profile: ${e}`)
|
|
314
|
-
return false
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
/**
|
|
319
|
-
* Run the auto-setup process for Bazarr
|
|
320
|
-
*/
|
|
321
|
-
async setup(options: AutoSetupOptions): Promise<AutoSetupResult> {
|
|
322
|
-
const { username, password } = options
|
|
323
|
-
|
|
324
|
-
try {
|
|
325
|
-
// Check if reachable
|
|
326
|
-
const healthy = await this.isHealthy()
|
|
327
|
-
if (!healthy) {
|
|
328
|
-
return { success: false, message: "Bazarr not reachable" }
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
// Get API key first (needed for subsequent requests)
|
|
332
|
-
const apiKey = await this.getApiKey()
|
|
333
|
-
if (apiKey) {
|
|
334
|
-
this.setApiKey(apiKey)
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
// Check if auth already configured
|
|
338
|
-
const initialized = await this.isInitialized()
|
|
339
|
-
let authConfigured = false
|
|
340
|
-
|
|
341
|
-
if (!initialized) {
|
|
342
|
-
// Enable form auth
|
|
343
|
-
authConfigured = await this.enableFormAuth(username, password)
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
return {
|
|
347
|
-
success: true,
|
|
348
|
-
message: initialized ? "Already configured" : authConfigured ? "Auth enabled" : "Ready",
|
|
349
|
-
data: { apiKey, authConfigured },
|
|
350
|
-
envUpdates: apiKey ? { API_KEY_BAZARR: apiKey } : undefined,
|
|
351
|
-
}
|
|
352
|
-
} catch (error) {
|
|
353
|
-
return { success: false, message: `${error}` }
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
}
|