@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/api/base-api.ts
DELETED
|
@@ -1,216 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Base API Client
|
|
3
|
-
* Abstract class providing shared fetch, logging, and error handling for all API clients.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { debugLog } from "~/utils/debug"
|
|
7
|
-
|
|
8
|
-
export interface ApiResponse<T> {
|
|
9
|
-
success: boolean
|
|
10
|
-
data?: T
|
|
11
|
-
error?: string
|
|
12
|
-
status?: number
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export abstract class BaseApiClient {
|
|
16
|
-
protected host: string
|
|
17
|
-
protected port: number
|
|
18
|
-
protected abstract readonly logPrefix: string
|
|
19
|
-
|
|
20
|
-
constructor(host: string, port: number) {
|
|
21
|
-
this.host = host
|
|
22
|
-
this.port = port
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Base URL for the API (override in subclass if protocol differs)
|
|
27
|
-
*/
|
|
28
|
-
protected get baseUrl(): string {
|
|
29
|
-
return `http://${this.host}:${this.port}`
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Build API URL for a given endpoint
|
|
34
|
-
*/
|
|
35
|
-
protected buildUrl(endpoint: string, basePath: string = ""): string {
|
|
36
|
-
return `${this.baseUrl}${basePath}${endpoint}`
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Generic GET request with logging and error handling
|
|
41
|
-
*/
|
|
42
|
-
protected async get<T>(
|
|
43
|
-
endpoint: string,
|
|
44
|
-
options: { basePath?: string; headers?: Record<string, string> } = {}
|
|
45
|
-
): Promise<ApiResponse<T>> {
|
|
46
|
-
const url = this.buildUrl(endpoint, options.basePath)
|
|
47
|
-
try {
|
|
48
|
-
debugLog(this.logPrefix, `GET ${endpoint}`)
|
|
49
|
-
const response = await fetch(url, {
|
|
50
|
-
method: "GET",
|
|
51
|
-
headers: options.headers,
|
|
52
|
-
})
|
|
53
|
-
if (!response.ok) {
|
|
54
|
-
debugLog(this.logPrefix, `GET ${endpoint} failed: ${response.status}`)
|
|
55
|
-
return { success: false, status: response.status }
|
|
56
|
-
}
|
|
57
|
-
const data = (await response.json()) as T
|
|
58
|
-
return { success: true, data }
|
|
59
|
-
} catch (error) {
|
|
60
|
-
debugLog(this.logPrefix, `GET ${endpoint} error: ${error}`)
|
|
61
|
-
return { success: false, error: String(error) }
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Generic GET request returning plain text
|
|
67
|
-
*/
|
|
68
|
-
protected async getText(
|
|
69
|
-
endpoint: string,
|
|
70
|
-
options: { basePath?: string; headers?: Record<string, string> } = {}
|
|
71
|
-
): Promise<ApiResponse<string>> {
|
|
72
|
-
const url = this.buildUrl(endpoint, options.basePath)
|
|
73
|
-
try {
|
|
74
|
-
debugLog(this.logPrefix, `GET (text) ${endpoint}`)
|
|
75
|
-
const response = await fetch(url, {
|
|
76
|
-
method: "GET",
|
|
77
|
-
headers: options.headers,
|
|
78
|
-
})
|
|
79
|
-
if (!response.ok) {
|
|
80
|
-
debugLog(this.logPrefix, `GET ${endpoint} failed: ${response.status}`)
|
|
81
|
-
return { success: false, status: response.status }
|
|
82
|
-
}
|
|
83
|
-
const data = await response.text()
|
|
84
|
-
return { success: true, data }
|
|
85
|
-
} catch (error) {
|
|
86
|
-
debugLog(this.logPrefix, `GET ${endpoint} error: ${error}`)
|
|
87
|
-
return { success: false, error: String(error) }
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Generic POST request with logging and error handling
|
|
93
|
-
*/
|
|
94
|
-
protected async post<T, B = unknown>(
|
|
95
|
-
endpoint: string,
|
|
96
|
-
body?: B,
|
|
97
|
-
options: { basePath?: string; headers?: Record<string, string> } = {}
|
|
98
|
-
): Promise<ApiResponse<T>> {
|
|
99
|
-
const url = this.buildUrl(endpoint, options.basePath)
|
|
100
|
-
try {
|
|
101
|
-
debugLog(this.logPrefix, `POST ${endpoint}`)
|
|
102
|
-
const response = await fetch(url, {
|
|
103
|
-
method: "POST",
|
|
104
|
-
headers: {
|
|
105
|
-
"Content-Type": "application/json",
|
|
106
|
-
...options.headers,
|
|
107
|
-
},
|
|
108
|
-
body: body ? JSON.stringify(body) : undefined,
|
|
109
|
-
})
|
|
110
|
-
if (!response.ok) {
|
|
111
|
-
debugLog(this.logPrefix, `POST ${endpoint} failed: ${response.status}`)
|
|
112
|
-
return { success: false, status: response.status }
|
|
113
|
-
}
|
|
114
|
-
// Handle empty responses
|
|
115
|
-
const text = await response.text()
|
|
116
|
-
if (!text) {
|
|
117
|
-
return { success: true }
|
|
118
|
-
}
|
|
119
|
-
try {
|
|
120
|
-
const data = JSON.parse(text) as T
|
|
121
|
-
return { success: true, data }
|
|
122
|
-
} catch {
|
|
123
|
-
// Response was not JSON
|
|
124
|
-
return { success: true }
|
|
125
|
-
}
|
|
126
|
-
} catch (error) {
|
|
127
|
-
debugLog(this.logPrefix, `POST ${endpoint} error: ${error}`)
|
|
128
|
-
return { success: false, error: String(error) }
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* Generic PUT request with logging and error handling
|
|
134
|
-
*/
|
|
135
|
-
protected async put<T, B = unknown>(
|
|
136
|
-
endpoint: string,
|
|
137
|
-
body?: B,
|
|
138
|
-
options: { basePath?: string; headers?: Record<string, string> } = {}
|
|
139
|
-
): Promise<ApiResponse<T>> {
|
|
140
|
-
const url = this.buildUrl(endpoint, options.basePath)
|
|
141
|
-
try {
|
|
142
|
-
debugLog(this.logPrefix, `PUT ${endpoint}`)
|
|
143
|
-
const response = await fetch(url, {
|
|
144
|
-
method: "PUT",
|
|
145
|
-
headers: {
|
|
146
|
-
"Content-Type": "application/json",
|
|
147
|
-
...options.headers,
|
|
148
|
-
},
|
|
149
|
-
body: body ? JSON.stringify(body) : undefined,
|
|
150
|
-
})
|
|
151
|
-
if (!response.ok) {
|
|
152
|
-
debugLog(this.logPrefix, `PUT ${endpoint} failed: ${response.status}`)
|
|
153
|
-
return { success: false, status: response.status }
|
|
154
|
-
}
|
|
155
|
-
const text = await response.text()
|
|
156
|
-
if (!text) {
|
|
157
|
-
return { success: true }
|
|
158
|
-
}
|
|
159
|
-
try {
|
|
160
|
-
const data = JSON.parse(text) as T
|
|
161
|
-
return { success: true, data }
|
|
162
|
-
} catch {
|
|
163
|
-
return { success: true }
|
|
164
|
-
}
|
|
165
|
-
} catch (error) {
|
|
166
|
-
debugLog(this.logPrefix, `PUT ${endpoint} error: ${error}`)
|
|
167
|
-
return { success: false, error: String(error) }
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
/**
|
|
172
|
-
* Generic DELETE request with logging and error handling
|
|
173
|
-
*/
|
|
174
|
-
protected async delete<T>(
|
|
175
|
-
endpoint: string,
|
|
176
|
-
options: { basePath?: string; headers?: Record<string, string> } = {}
|
|
177
|
-
): Promise<ApiResponse<T>> {
|
|
178
|
-
const url = this.buildUrl(endpoint, options.basePath)
|
|
179
|
-
try {
|
|
180
|
-
debugLog(this.logPrefix, `DELETE ${endpoint}`)
|
|
181
|
-
const response = await fetch(url, {
|
|
182
|
-
method: "DELETE",
|
|
183
|
-
headers: options.headers,
|
|
184
|
-
})
|
|
185
|
-
if (!response.ok) {
|
|
186
|
-
debugLog(this.logPrefix, `DELETE ${endpoint} failed: ${response.status}`)
|
|
187
|
-
return { success: false, status: response.status }
|
|
188
|
-
}
|
|
189
|
-
const text = await response.text()
|
|
190
|
-
if (!text) {
|
|
191
|
-
return { success: true }
|
|
192
|
-
}
|
|
193
|
-
try {
|
|
194
|
-
const data = JSON.parse(text) as T
|
|
195
|
-
return { success: true, data }
|
|
196
|
-
} catch {
|
|
197
|
-
return { success: true }
|
|
198
|
-
}
|
|
199
|
-
} catch (error) {
|
|
200
|
-
debugLog(this.logPrefix, `DELETE ${endpoint} error: ${error}`)
|
|
201
|
-
return { success: false, error: String(error) }
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
/**
|
|
206
|
-
* Simple health check - override in subclass for custom logic
|
|
207
|
-
*/
|
|
208
|
-
async isHealthy(): Promise<boolean> {
|
|
209
|
-
try {
|
|
210
|
-
const response = await fetch(this.baseUrl, { method: "HEAD" })
|
|
211
|
-
return response.ok
|
|
212
|
-
} catch {
|
|
213
|
-
return false
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
}
|
package/src/api/bazarr-api.ts
DELETED
|
@@ -1,297 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Bazarr API Client
|
|
3
|
-
* Handles Bazarr-specific API calls for authentication and settings
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import type { AutoSetupOptions, AutoSetupResult, IAutoSetupClient } from "./auto-setup-types"
|
|
7
|
-
import { debugLog } from "~/utils/debug"
|
|
8
|
-
import { BaseApiClient } from "./base-api"
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Bazarr Language Profile Structure
|
|
12
|
-
*/
|
|
13
|
-
export interface BazarrLanguageProfile {
|
|
14
|
-
name: string
|
|
15
|
-
cutoff: string
|
|
16
|
-
languages: {
|
|
17
|
-
code: string
|
|
18
|
-
forced: boolean
|
|
19
|
-
hi: boolean
|
|
20
|
-
}[]
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Bazarr System Settings (partial - auth related fields)
|
|
25
|
-
*/
|
|
26
|
-
export interface BazarrAuthSettings {
|
|
27
|
-
auth: {
|
|
28
|
-
type: "None" | "Basic" | "Form"
|
|
29
|
-
username: string
|
|
30
|
-
password: string
|
|
31
|
-
apikey: string
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Bazarr API Client
|
|
37
|
-
* Note: Bazarr uses form data for POST, not JSON!
|
|
38
|
-
*/
|
|
39
|
-
export class BazarrApiClient extends BaseApiClient implements IAutoSetupClient {
|
|
40
|
-
protected readonly logPrefix = "Bazarr"
|
|
41
|
-
private apiKey: string | null = null
|
|
42
|
-
|
|
43
|
-
constructor(host: string, port: number) {
|
|
44
|
-
super(host, port)
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Set API key for authentication
|
|
49
|
-
*/
|
|
50
|
-
setApiKey(key: string): void {
|
|
51
|
-
this.apiKey = key
|
|
52
|
-
debugLog("Bazarr", `API key set`)
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Build API URL with optional API key
|
|
57
|
-
*/
|
|
58
|
-
private buildApiUrlWithKey(endpoint: string): string {
|
|
59
|
-
let url = `${this.baseUrl}/api${endpoint}`
|
|
60
|
-
if (this.apiKey) {
|
|
61
|
-
url = `${url}${url.includes("?") ? "&" : "?"}apikey=${this.apiKey}`
|
|
62
|
-
}
|
|
63
|
-
return url
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Make a GET request to Bazarr API
|
|
68
|
-
*/
|
|
69
|
-
private async getJson<T>(endpoint: string): Promise<T> {
|
|
70
|
-
const url = this.buildApiUrlWithKey(endpoint)
|
|
71
|
-
debugLog("Bazarr", `GET ${url}`)
|
|
72
|
-
|
|
73
|
-
const response = await fetch(url, {
|
|
74
|
-
method: "GET",
|
|
75
|
-
headers: { Accept: "application/json" },
|
|
76
|
-
})
|
|
77
|
-
|
|
78
|
-
if (!response.ok) {
|
|
79
|
-
throw new Error(`Bazarr API error: ${response.status} ${response.statusText}`)
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
const text = await response.text()
|
|
83
|
-
if (!text) return {} as T
|
|
84
|
-
return JSON.parse(text) as T
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* Make a POST request using form data (NOT JSON)
|
|
89
|
-
*/
|
|
90
|
-
private async postForm(endpoint: string, data: Record<string, string>): Promise<void> {
|
|
91
|
-
const url = this.buildApiUrlWithKey(endpoint)
|
|
92
|
-
const formData = new URLSearchParams()
|
|
93
|
-
for (const [key, value] of Object.entries(data)) {
|
|
94
|
-
formData.append(key, value)
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
debugLog("Bazarr", `POST ${url}`)
|
|
98
|
-
|
|
99
|
-
const response = await fetch(url, {
|
|
100
|
-
method: "POST",
|
|
101
|
-
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
102
|
-
body: formData.toString(),
|
|
103
|
-
})
|
|
104
|
-
|
|
105
|
-
if (!response.ok) {
|
|
106
|
-
throw new Error(`Bazarr API error: ${response.status} ${response.statusText}`)
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* Check if Bazarr is healthy
|
|
112
|
-
*/
|
|
113
|
-
async isHealthy(): Promise<boolean> {
|
|
114
|
-
try {
|
|
115
|
-
await this.getJson("/system/status")
|
|
116
|
-
return true
|
|
117
|
-
} catch {
|
|
118
|
-
return false
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
/**
|
|
123
|
-
* Get current system settings
|
|
124
|
-
*/
|
|
125
|
-
async getSettings(): Promise<Record<string, unknown>> {
|
|
126
|
-
return this.getJson<Record<string, unknown>>("/system/settings")
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
* Update authentication settings
|
|
131
|
-
*/
|
|
132
|
-
async enableFormAuth(username: string, password: string, override = false): Promise<boolean> {
|
|
133
|
-
try {
|
|
134
|
-
const currentSettings = await this.getSettings()
|
|
135
|
-
const currentAuth = (currentSettings as { auth?: { type?: string } }).auth
|
|
136
|
-
|
|
137
|
-
if (currentAuth?.type && currentAuth.type !== "None" && !override) {
|
|
138
|
-
debugLog("Bazarr", `Auth already configured (type: ${currentAuth.type}), skipping`)
|
|
139
|
-
return false
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
await this.postForm("/system/settings", {
|
|
143
|
-
"settings-auth-type": "form",
|
|
144
|
-
"settings-auth-username": username,
|
|
145
|
-
"settings-auth-password": password,
|
|
146
|
-
})
|
|
147
|
-
|
|
148
|
-
debugLog("Bazarr", `Form auth enabled for user: ${username}`)
|
|
149
|
-
return true
|
|
150
|
-
} catch (e) {
|
|
151
|
-
debugLog("Bazarr", `Failed to enable form auth: ${e}`)
|
|
152
|
-
throw e
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
/**
|
|
157
|
-
* Get API key from settings
|
|
158
|
-
*/
|
|
159
|
-
async getApiKey(): Promise<string | null> {
|
|
160
|
-
try {
|
|
161
|
-
const settings = await this.getSettings()
|
|
162
|
-
const auth = (settings as unknown as BazarrAuthSettings).auth
|
|
163
|
-
return auth?.apikey || null
|
|
164
|
-
} catch {
|
|
165
|
-
return null
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
/**
|
|
170
|
-
* Configure Radarr connection
|
|
171
|
-
*/
|
|
172
|
-
async configureRadarr(host: string, port: number, apiKey: string): Promise<boolean> {
|
|
173
|
-
await this.postForm("/system/settings", {
|
|
174
|
-
"settings-radarr-ip": host,
|
|
175
|
-
"settings-radarr-port": String(port),
|
|
176
|
-
"settings-radarr-apikey": apiKey,
|
|
177
|
-
"settings-radarr-base_url": "",
|
|
178
|
-
"settings-radarr-ssl": "false",
|
|
179
|
-
"settings-general-use_radarr": "true",
|
|
180
|
-
})
|
|
181
|
-
return true
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
/**
|
|
185
|
-
* Configure Sonarr connection
|
|
186
|
-
*/
|
|
187
|
-
async configureSonarr(host: string, port: number, apiKey: string): Promise<boolean> {
|
|
188
|
-
await this.postForm("/system/settings", {
|
|
189
|
-
"settings-sonarr-ip": host,
|
|
190
|
-
"settings-sonarr-port": String(port),
|
|
191
|
-
"settings-sonarr-apikey": apiKey,
|
|
192
|
-
"settings-sonarr-base_url": "",
|
|
193
|
-
"settings-sonarr-ssl": "false",
|
|
194
|
-
"settings-general-use_sonarr": "true",
|
|
195
|
-
})
|
|
196
|
-
return true
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
/**
|
|
200
|
-
* Check if already configured
|
|
201
|
-
*/
|
|
202
|
-
async isInitialized(): Promise<boolean> {
|
|
203
|
-
try {
|
|
204
|
-
const settings = await this.getSettings()
|
|
205
|
-
const auth = (settings as { auth?: { type?: string } }).auth
|
|
206
|
-
return !!auth?.type && auth.type !== "None"
|
|
207
|
-
} catch {
|
|
208
|
-
return false
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
/**
|
|
213
|
-
* Configure General Settings
|
|
214
|
-
*/
|
|
215
|
-
async configureGeneralSettings(): Promise<boolean> {
|
|
216
|
-
try {
|
|
217
|
-
await this.postForm("/system/settings", {
|
|
218
|
-
"settings-subtitles-use_embedded_subtitles": "true",
|
|
219
|
-
"settings-subtitles-autosearch": "true",
|
|
220
|
-
"settings-subtitles-path_mapping": "",
|
|
221
|
-
})
|
|
222
|
-
return true
|
|
223
|
-
} catch {
|
|
224
|
-
return false
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
/**
|
|
229
|
-
* Get all language profiles
|
|
230
|
-
*/
|
|
231
|
-
async getLanguageProfiles(): Promise<BazarrLanguageProfile[]> {
|
|
232
|
-
return this.getJson<BazarrLanguageProfile[]>("/system/languages/profiles")
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
/**
|
|
236
|
-
* Configure Default Language Profile
|
|
237
|
-
*/
|
|
238
|
-
async configureDefaultLanguageProfile(name = "English", language = "en"): Promise<boolean> {
|
|
239
|
-
try {
|
|
240
|
-
const profiles = (await this.getLanguageProfiles()) || []
|
|
241
|
-
const existing = profiles.find((p) => p.name === name)
|
|
242
|
-
|
|
243
|
-
if (existing) {
|
|
244
|
-
return true
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
const newProfile: BazarrLanguageProfile = {
|
|
248
|
-
name,
|
|
249
|
-
cutoff: language,
|
|
250
|
-
languages: [{ code: language, forced: false, hi: false }],
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
profiles.push(newProfile)
|
|
254
|
-
await this.postForm("/system/settings", {
|
|
255
|
-
languages_profiles: JSON.stringify(profiles),
|
|
256
|
-
})
|
|
257
|
-
return true
|
|
258
|
-
} catch {
|
|
259
|
-
return false
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
/**
|
|
264
|
-
* Run the auto-setup process
|
|
265
|
-
*/
|
|
266
|
-
async setup(options: AutoSetupOptions): Promise<AutoSetupResult> {
|
|
267
|
-
const { username, password } = options
|
|
268
|
-
|
|
269
|
-
try {
|
|
270
|
-
const healthy = await this.isHealthy()
|
|
271
|
-
if (!healthy) {
|
|
272
|
-
return { success: false, message: "Bazarr not reachable" }
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
const apiKey = await this.getApiKey()
|
|
276
|
-
if (apiKey) {
|
|
277
|
-
this.setApiKey(apiKey)
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
const initialized = await this.isInitialized()
|
|
281
|
-
let authConfigured = false
|
|
282
|
-
|
|
283
|
-
if (!initialized) {
|
|
284
|
-
authConfigured = await this.enableFormAuth(username, password)
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
return {
|
|
288
|
-
success: true,
|
|
289
|
-
message: initialized ? "Already configured" : authConfigured ? "Auth enabled" : "Ready",
|
|
290
|
-
data: { apiKey, authConfigured },
|
|
291
|
-
envUpdates: apiKey ? { API_KEY_BAZARR: apiKey } : undefined,
|
|
292
|
-
}
|
|
293
|
-
} catch (error) {
|
|
294
|
-
return { success: false, message: `${error}` }
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
}
|