@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,461 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Maintainerr API Client
|
|
3
|
-
* Handles Maintainerr integration for automated media management
|
|
4
|
-
* API docs: https://github.com/Maintainerr/Maintainerr
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import type { AutoSetupOptions, AutoSetupResult, IAutoSetupClient } from "./auto-setup-types"
|
|
8
|
-
import { BaseApiClient } from "./base-api"
|
|
9
|
-
|
|
10
|
-
// === Response Types ===
|
|
11
|
-
|
|
12
|
-
export interface MaintainerrVersionInfo {
|
|
13
|
-
version: string
|
|
14
|
-
commitTag?: string
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export interface MaintainerrCollection {
|
|
18
|
-
id: number
|
|
19
|
-
libraryId: number
|
|
20
|
-
title: string
|
|
21
|
-
description?: string
|
|
22
|
-
isActive: boolean
|
|
23
|
-
arrAction: number
|
|
24
|
-
visibleOnHome?: boolean
|
|
25
|
-
deleteAfterDays?: number
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export interface MaintainerrRuleGroup {
|
|
29
|
-
id: number
|
|
30
|
-
libraryId: number
|
|
31
|
-
name: string
|
|
32
|
-
description?: string
|
|
33
|
-
isActive: boolean
|
|
34
|
-
arrAction: number
|
|
35
|
-
useRules: boolean
|
|
36
|
-
dataType: number
|
|
37
|
-
rules?: MaintainerrRule[]
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export interface MaintainerrRule {
|
|
41
|
-
operator: number | null
|
|
42
|
-
action: number
|
|
43
|
-
firstVal: number[]
|
|
44
|
-
lastVal?: number[]
|
|
45
|
-
customVal?: { ruleTypeId: number; value: string }
|
|
46
|
-
section: number
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export interface MaintainerrTaskStatus {
|
|
50
|
-
time?: string
|
|
51
|
-
running: boolean
|
|
52
|
-
runningSince?: string
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
export interface MaintainerrSettings {
|
|
56
|
-
plex_name?: string
|
|
57
|
-
plex_hostname?: string
|
|
58
|
-
plex_port?: number
|
|
59
|
-
plex_ssl?: boolean
|
|
60
|
-
plex_auth_token?: string
|
|
61
|
-
radarr_url?: string
|
|
62
|
-
radarr_api_key?: string
|
|
63
|
-
sonarr_url?: string
|
|
64
|
-
sonarr_api_key?: string
|
|
65
|
-
overseerr_url?: string
|
|
66
|
-
overseerr_api_key?: string
|
|
67
|
-
tautulli_url?: string
|
|
68
|
-
tautulli_api_key?: string
|
|
69
|
-
collection_handler_job_cron?: string
|
|
70
|
-
rules_handler_job_cron?: string
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
export interface MaintainerrSettingsUpdate {
|
|
74
|
-
plex_name?: string
|
|
75
|
-
plex_hostname?: string
|
|
76
|
-
plex_port?: number
|
|
77
|
-
plex_ssl?: boolean
|
|
78
|
-
plex_auth_token?: string
|
|
79
|
-
overseerr_url?: string
|
|
80
|
-
overseerr_api_key?: string
|
|
81
|
-
tautulli_url?: string
|
|
82
|
-
tautulli_api_key?: string
|
|
83
|
-
collection_handler_job_cron?: string
|
|
84
|
-
rules_handler_job_cron?: string
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
export interface MaintainerrLibrary {
|
|
88
|
-
key: string
|
|
89
|
-
title: string
|
|
90
|
-
type: "movie" | "show"
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
export interface PlexServerConnection {
|
|
94
|
-
protocol: string
|
|
95
|
-
address: string
|
|
96
|
-
port: number
|
|
97
|
-
uri: string
|
|
98
|
-
local: boolean
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
export interface PlexServerDevice {
|
|
102
|
-
name: string
|
|
103
|
-
product: string
|
|
104
|
-
productVersion: string
|
|
105
|
-
platform: string
|
|
106
|
-
clientIdentifier: string
|
|
107
|
-
owned: boolean
|
|
108
|
-
accessToken: string
|
|
109
|
-
connection: PlexServerConnection[]
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
// === API Client ===
|
|
113
|
-
|
|
114
|
-
export class MaintainerrClient extends BaseApiClient implements IAutoSetupClient {
|
|
115
|
-
protected readonly logPrefix = "MaintainerrApi"
|
|
116
|
-
|
|
117
|
-
constructor(host: string, port: number = 6246) {
|
|
118
|
-
super(host, port)
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
private buildApiUrl(endpoint: string): string {
|
|
122
|
-
return `${this.baseUrl}/api${endpoint}`
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
// === Health & Status ===
|
|
126
|
-
|
|
127
|
-
async isHealthy(): Promise<boolean> {
|
|
128
|
-
try {
|
|
129
|
-
const response = await fetch(this.buildApiUrl("/settings/version"), { method: "GET" })
|
|
130
|
-
return response.ok
|
|
131
|
-
} catch {
|
|
132
|
-
return false
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
async isInitialized(): Promise<boolean> {
|
|
137
|
-
try {
|
|
138
|
-
const response = await fetch(this.buildApiUrl("/settings/test/setup"), { method: "GET" })
|
|
139
|
-
return response.ok
|
|
140
|
-
} catch {
|
|
141
|
-
return false
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
async getVersion(): Promise<MaintainerrVersionInfo | null> {
|
|
146
|
-
try {
|
|
147
|
-
const response = await fetch(this.buildApiUrl("/settings/version"), { method: "GET" })
|
|
148
|
-
if (response.ok) {
|
|
149
|
-
const versionText = await response.text()
|
|
150
|
-
return { version: versionText.trim() }
|
|
151
|
-
}
|
|
152
|
-
} catch {
|
|
153
|
-
// Ignore
|
|
154
|
-
}
|
|
155
|
-
return null
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
// === Collections API ===
|
|
159
|
-
|
|
160
|
-
async getCollections(libraryId?: number): Promise<MaintainerrCollection[]> {
|
|
161
|
-
try {
|
|
162
|
-
const url = libraryId
|
|
163
|
-
? this.buildApiUrl(`/collections?libraryId=${libraryId}`)
|
|
164
|
-
: this.buildApiUrl("/collections")
|
|
165
|
-
const response = await fetch(url, { method: "GET" })
|
|
166
|
-
if (response.ok) {
|
|
167
|
-
return (await response.json()) as MaintainerrCollection[]
|
|
168
|
-
}
|
|
169
|
-
} catch {
|
|
170
|
-
// Ignore
|
|
171
|
-
}
|
|
172
|
-
return []
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
async getCollection(id: number): Promise<MaintainerrCollection | null> {
|
|
176
|
-
try {
|
|
177
|
-
const response = await fetch(this.buildApiUrl(`/collections/collection/${id}`), {
|
|
178
|
-
method: "GET",
|
|
179
|
-
})
|
|
180
|
-
if (response.ok) {
|
|
181
|
-
return (await response.json()) as MaintainerrCollection
|
|
182
|
-
}
|
|
183
|
-
} catch {
|
|
184
|
-
// Ignore
|
|
185
|
-
}
|
|
186
|
-
return null
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
// === Rules API ===
|
|
190
|
-
|
|
191
|
-
async getRules(activeOnly: boolean = false, libraryId?: number): Promise<MaintainerrRuleGroup[]> {
|
|
192
|
-
try {
|
|
193
|
-
const params = new URLSearchParams()
|
|
194
|
-
if (activeOnly) params.set("activeOnly", "true")
|
|
195
|
-
if (libraryId) params.set("libraryId", libraryId.toString())
|
|
196
|
-
const queryString = params.toString()
|
|
197
|
-
const url = queryString
|
|
198
|
-
? this.buildApiUrl(`/rules?${queryString}`)
|
|
199
|
-
: this.buildApiUrl("/rules")
|
|
200
|
-
const response = await fetch(url, { method: "GET" })
|
|
201
|
-
if (response.ok) {
|
|
202
|
-
return (await response.json()) as MaintainerrRuleGroup[]
|
|
203
|
-
}
|
|
204
|
-
} catch {
|
|
205
|
-
// Ignore
|
|
206
|
-
}
|
|
207
|
-
return []
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
async executeRules(): Promise<boolean> {
|
|
211
|
-
try {
|
|
212
|
-
const response = await fetch(this.buildApiUrl("/rules/execute"), { method: "POST" })
|
|
213
|
-
return response.ok
|
|
214
|
-
} catch {
|
|
215
|
-
return false
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
// === Tasks API ===
|
|
220
|
-
|
|
221
|
-
async getTaskStatus(
|
|
222
|
-
taskName: "rule-executor" | "collection-handler"
|
|
223
|
-
): Promise<MaintainerrTaskStatus | null> {
|
|
224
|
-
try {
|
|
225
|
-
const response = await fetch(this.buildApiUrl(`/tasks/${taskName}/status`), { method: "GET" })
|
|
226
|
-
if (response.ok) {
|
|
227
|
-
return (await response.json()) as MaintainerrTaskStatus
|
|
228
|
-
}
|
|
229
|
-
} catch {
|
|
230
|
-
// Ignore
|
|
231
|
-
}
|
|
232
|
-
return null
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
// === Plex API ===
|
|
236
|
-
|
|
237
|
-
async getPlexLibraries(): Promise<MaintainerrLibrary[]> {
|
|
238
|
-
try {
|
|
239
|
-
const response = await fetch(this.buildApiUrl("/plex/libraries"), { method: "GET" })
|
|
240
|
-
if (response.ok) {
|
|
241
|
-
return (await response.json()) as MaintainerrLibrary[]
|
|
242
|
-
}
|
|
243
|
-
} catch {
|
|
244
|
-
// Ignore
|
|
245
|
-
}
|
|
246
|
-
return []
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
async testPlexConnection(): Promise<boolean> {
|
|
250
|
-
try {
|
|
251
|
-
const response = await fetch(this.buildApiUrl("/settings/test/plex"), { method: "GET" })
|
|
252
|
-
return response.ok
|
|
253
|
-
} catch {
|
|
254
|
-
return false
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
// === Settings API ===
|
|
259
|
-
|
|
260
|
-
async getSettings(): Promise<MaintainerrSettings | null> {
|
|
261
|
-
try {
|
|
262
|
-
const response = await fetch(this.buildApiUrl("/settings"), { method: "GET" })
|
|
263
|
-
if (response.ok) {
|
|
264
|
-
return (await response.json()) as MaintainerrSettings
|
|
265
|
-
}
|
|
266
|
-
} catch {
|
|
267
|
-
// Ignore
|
|
268
|
-
}
|
|
269
|
-
return null
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
async updateSettings(settings: MaintainerrSettingsUpdate): Promise<boolean> {
|
|
273
|
-
try {
|
|
274
|
-
const currentSettings = await this.getSettings()
|
|
275
|
-
if (!currentSettings) return false
|
|
276
|
-
|
|
277
|
-
const mergedSettings = { ...currentSettings, ...settings }
|
|
278
|
-
const response = await fetch(this.buildApiUrl("/settings"), {
|
|
279
|
-
method: "POST",
|
|
280
|
-
headers: { "Content-Type": "application/json" },
|
|
281
|
-
body: JSON.stringify(mergedSettings),
|
|
282
|
-
})
|
|
283
|
-
return response.ok
|
|
284
|
-
} catch {
|
|
285
|
-
return false
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
async configureRadarr(host: string, port: number, apiKey: string): Promise<boolean> {
|
|
290
|
-
try {
|
|
291
|
-
const response = await fetch(this.buildApiUrl("/settings/radarr"), {
|
|
292
|
-
method: "POST",
|
|
293
|
-
headers: { "Content-Type": "application/json" },
|
|
294
|
-
body: JSON.stringify({
|
|
295
|
-
url: `http://${host}:${port}`,
|
|
296
|
-
apiKey,
|
|
297
|
-
serverName: host,
|
|
298
|
-
}),
|
|
299
|
-
})
|
|
300
|
-
if (response.ok) {
|
|
301
|
-
const result = await response.json()
|
|
302
|
-
return result?.status === "OK"
|
|
303
|
-
}
|
|
304
|
-
return false
|
|
305
|
-
} catch {
|
|
306
|
-
return false
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
async configureSonarr(host: string, port: number, apiKey: string): Promise<boolean> {
|
|
311
|
-
try {
|
|
312
|
-
const response = await fetch(this.buildApiUrl("/settings/sonarr"), {
|
|
313
|
-
method: "POST",
|
|
314
|
-
headers: { "Content-Type": "application/json" },
|
|
315
|
-
body: JSON.stringify({
|
|
316
|
-
url: `http://${host}:${port}`,
|
|
317
|
-
apiKey,
|
|
318
|
-
serverName: host,
|
|
319
|
-
}),
|
|
320
|
-
})
|
|
321
|
-
if (response.ok) {
|
|
322
|
-
const result = await response.json()
|
|
323
|
-
return result?.status === "OK"
|
|
324
|
-
}
|
|
325
|
-
return false
|
|
326
|
-
} catch {
|
|
327
|
-
return false
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
async configureOverseerr(host: string, port: number, apiKey: string): Promise<boolean> {
|
|
332
|
-
return this.updateSettings({
|
|
333
|
-
overseerr_url: `http://${host}:${port}`,
|
|
334
|
-
overseerr_api_key: apiKey,
|
|
335
|
-
})
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
async configureTautulli(host: string, port: number, apiKey: string): Promise<boolean> {
|
|
339
|
-
return this.updateSettings({
|
|
340
|
-
tautulli_url: `http://${host}:${port}`,
|
|
341
|
-
tautulli_api_key: apiKey,
|
|
342
|
-
})
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
async generateApiKey(): Promise<string | null> {
|
|
346
|
-
try {
|
|
347
|
-
const response = await fetch(this.buildApiUrl("/settings/api/generate"), { method: "GET" })
|
|
348
|
-
if (response.ok) {
|
|
349
|
-
const apiKey = await response.text()
|
|
350
|
-
return apiKey.trim() || null
|
|
351
|
-
}
|
|
352
|
-
} catch {
|
|
353
|
-
// Ignore
|
|
354
|
-
}
|
|
355
|
-
return null
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
async getPlexServers(): Promise<PlexServerDevice[] | null> {
|
|
359
|
-
try {
|
|
360
|
-
const response = await fetch(this.buildApiUrl("/settings/plex/devices/servers"), {
|
|
361
|
-
method: "GET",
|
|
362
|
-
})
|
|
363
|
-
if (response.ok) {
|
|
364
|
-
return (await response.json()) as PlexServerDevice[]
|
|
365
|
-
}
|
|
366
|
-
} catch {
|
|
367
|
-
// Ignore
|
|
368
|
-
}
|
|
369
|
-
return null
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
async setPlexToken(token: string): Promise<boolean> {
|
|
373
|
-
try {
|
|
374
|
-
const response = await fetch(this.buildApiUrl("/settings/plex/token"), {
|
|
375
|
-
method: "POST",
|
|
376
|
-
headers: { "Content-Type": "application/json" },
|
|
377
|
-
body: JSON.stringify({ plex_auth_token: token }),
|
|
378
|
-
})
|
|
379
|
-
return response.ok
|
|
380
|
-
} catch {
|
|
381
|
-
return false
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
async configurePlexServer(
|
|
386
|
-
hostname: string,
|
|
387
|
-
port: number,
|
|
388
|
-
name: string,
|
|
389
|
-
ssl: boolean = false
|
|
390
|
-
): Promise<boolean> {
|
|
391
|
-
return this.updateSettings({
|
|
392
|
-
plex_hostname: hostname,
|
|
393
|
-
plex_port: port,
|
|
394
|
-
plex_name: name,
|
|
395
|
-
plex_ssl: ssl,
|
|
396
|
-
})
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
// === Auto-Setup ===
|
|
400
|
-
|
|
401
|
-
async setup(options: AutoSetupOptions): Promise<AutoSetupResult> {
|
|
402
|
-
try {
|
|
403
|
-
const healthy = await this.isHealthy()
|
|
404
|
-
if (!healthy) {
|
|
405
|
-
return { success: false, message: "Maintainerr not reachable" }
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
const version = await this.getVersion()
|
|
409
|
-
if (!version) {
|
|
410
|
-
return { success: false, message: "Failed to get Maintainerr version" }
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
const apiKey = await this.generateApiKey()
|
|
414
|
-
const envUpdates: Record<string, string> = {}
|
|
415
|
-
if (apiKey) {
|
|
416
|
-
envUpdates["API_KEY_MAINTAINERR"] = apiKey
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
const plexToken = options.plexToken || options.env["API_KEY_PLEX"]
|
|
420
|
-
let plexConnected = false
|
|
421
|
-
if (plexToken) {
|
|
422
|
-
const plexSet = await this.setPlexToken(plexToken)
|
|
423
|
-
if (plexSet) {
|
|
424
|
-
const servers = await this.getPlexServers()
|
|
425
|
-
if (servers && servers.length > 0) {
|
|
426
|
-
const server = servers[0]
|
|
427
|
-
const localConn = server.connection.find(
|
|
428
|
-
(c) => c.local && c.address.startsWith("192.168")
|
|
429
|
-
)
|
|
430
|
-
const conn = localConn || server.connection[0]
|
|
431
|
-
|
|
432
|
-
if (conn) {
|
|
433
|
-
await this.configurePlexServer(
|
|
434
|
-
conn.address,
|
|
435
|
-
conn.port,
|
|
436
|
-
server.name,
|
|
437
|
-
conn.protocol === "https"
|
|
438
|
-
)
|
|
439
|
-
}
|
|
440
|
-
}
|
|
441
|
-
plexConnected = await this.testPlexConnection()
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
return {
|
|
446
|
-
success: true,
|
|
447
|
-
message: plexConnected
|
|
448
|
-
? `Maintainerr v${version.version} connected to Plex`
|
|
449
|
-
: `Maintainerr v${version.version} ready`,
|
|
450
|
-
envUpdates: Object.keys(envUpdates).length > 0 ? envUpdates : undefined,
|
|
451
|
-
data: {
|
|
452
|
-
version: version.version,
|
|
453
|
-
apiKey,
|
|
454
|
-
requiresWizard: !plexConnected,
|
|
455
|
-
},
|
|
456
|
-
}
|
|
457
|
-
} catch (error) {
|
|
458
|
-
return { success: false, message: `${error}` }
|
|
459
|
-
}
|
|
460
|
-
}
|
|
461
|
-
}
|
package/src/api/naming-config.ts
DELETED
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
export interface RadarrNamingConfig {
|
|
2
|
-
renameMovies: boolean
|
|
3
|
-
replaceIllegalCharacters: boolean
|
|
4
|
-
colonReplacementFormat: "dash" | "spaceDash" | "spaceDashSpace" | "smart" | "delete" | number
|
|
5
|
-
standardMovieFormat: string
|
|
6
|
-
movieFolderFormat: string
|
|
7
|
-
includeQuality: boolean
|
|
8
|
-
replaceSpaces: boolean
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export interface SonarrNamingConfig {
|
|
12
|
-
renameEpisodes: boolean
|
|
13
|
-
replaceIllegalCharacters: boolean
|
|
14
|
-
colonReplacementFormat: "dash" | "spaceDash" | "spaceDashSpace" | "smart" | "delete" | number
|
|
15
|
-
multiEpisodeStyle:
|
|
16
|
-
| "extend"
|
|
17
|
-
| "duplicate"
|
|
18
|
-
| "repeat"
|
|
19
|
-
| "scene"
|
|
20
|
-
| "range"
|
|
21
|
-
| "prefixedRange"
|
|
22
|
-
| number
|
|
23
|
-
dailyEpisodeFormat: string
|
|
24
|
-
animeEpisodeFormat: string
|
|
25
|
-
seriesFolderFormat: string
|
|
26
|
-
seasonFolderFormat: string
|
|
27
|
-
standardEpisodeFormat: string
|
|
28
|
-
includeSeriesTitle: boolean
|
|
29
|
-
includeEpisodeTitle: boolean
|
|
30
|
-
includeQuality: boolean
|
|
31
|
-
replaceSpaces: boolean
|
|
32
|
-
separator: string
|
|
33
|
-
numberStyle: string
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export interface LidarrNamingConfig {
|
|
37
|
-
renameTracks: boolean
|
|
38
|
-
replaceIllegalCharacters: boolean
|
|
39
|
-
colonReplacementFormat: "dash" | "spaceDash" | "spaceDashSpace" | "smart" | "delete" | number
|
|
40
|
-
standardTrackFormat: string
|
|
41
|
-
multiDiscTrackFormat: string
|
|
42
|
-
artistFolderFormat: string
|
|
43
|
-
albumFolderFormat: string
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export type NamingConfig = RadarrNamingConfig | SonarrNamingConfig | LidarrNamingConfig
|
|
47
|
-
|
|
48
|
-
// TRaSH Guides Recommended Naming Schemes
|
|
49
|
-
// Source: https://trash-guides.info/Radarr/Radarr-recommended-naming-scheme/
|
|
50
|
-
// Source: https://trash-guides.info/Sonarr/Sonarr-recommended-naming-scheme/
|
|
51
|
-
// Lidarr: https://wiki.servarr.com/lidarr/settings#media-management
|
|
52
|
-
|
|
53
|
-
export const TRASH_NAMING_CONFIG = {
|
|
54
|
-
radarr: {
|
|
55
|
-
renameMovies: true,
|
|
56
|
-
replaceIllegalCharacters: true,
|
|
57
|
-
colonReplacementFormat: "dash",
|
|
58
|
-
standardMovieFormat:
|
|
59
|
-
"{Movie CleanTitle} ({Release Year}) {edition-{Edition Tags}} {[Custom Formats]}{[Quality Full]}{[MediaInfo 3D]}{[Mediainfo AudioCodec}{ Mediainfo AudioChannels]}{[MediaInfo VideoDynamicRangeType]}{[Mediainfo VideoCodec]}{-Release Group}",
|
|
60
|
-
movieFolderFormat: "{Movie CleanTitle} ({Release Year})",
|
|
61
|
-
includeQuality: true,
|
|
62
|
-
replaceSpaces: false,
|
|
63
|
-
} as RadarrNamingConfig,
|
|
64
|
-
|
|
65
|
-
sonarr: {
|
|
66
|
-
renameEpisodes: true,
|
|
67
|
-
replaceIllegalCharacters: true,
|
|
68
|
-
colonReplacementFormat: 1, // 1 = Dash
|
|
69
|
-
multiEpisodeStyle: 5, // 5 = Prefixed Range
|
|
70
|
-
standardEpisodeFormat:
|
|
71
|
-
"{Series TitleYear} - S{season:00}E{episode:00} - {Episode CleanTitle} {[Custom Formats]}{[Quality Full]}{[Mediainfo AudioCodec}{ Mediainfo AudioChannels]}{[MediaInfo VideoDynamicRangeType]}{[Mediainfo VideoCodec]}{-Release Group}",
|
|
72
|
-
dailyEpisodeFormat:
|
|
73
|
-
"{Series TitleYear} - {Air-Date} - {Episode CleanTitle} {[Custom Formats]}{[Quality Full]}{[MediaInfo 3D]}{[Mediainfo AudioCodec}{ Mediainfo AudioChannels]}{[MediaInfo VideoDynamicRangeType]}{[Mediainfo VideoCodec]}{-Release Group}",
|
|
74
|
-
animeEpisodeFormat:
|
|
75
|
-
"{Series TitleYear} - S{season:00}E{episode:00} - {absolute:000} - {Episode CleanTitle} {[Custom Formats]}{[Quality Full]}{[MediaInfo 3D]}{[Mediainfo AudioCodec}{ Mediainfo AudioChannels]}{MediaInfo AudioLanguages}{[MediaInfo VideoDynamicRangeType]}[{Mediainfo VideoCodec }{MediaInfo VideoBitDepth}bit]{-Release Group}",
|
|
76
|
-
seriesFolderFormat: "{Series TitleYear}",
|
|
77
|
-
seasonFolderFormat: "Season {season:00}",
|
|
78
|
-
includeSeriesTitle: true,
|
|
79
|
-
includeEpisodeTitle: true,
|
|
80
|
-
includeQuality: true,
|
|
81
|
-
replaceSpaces: false,
|
|
82
|
-
separator: " - ",
|
|
83
|
-
numberStyle: "S{season:00}E{episode:00}",
|
|
84
|
-
} as SonarrNamingConfig,
|
|
85
|
-
|
|
86
|
-
lidarr: {
|
|
87
|
-
renameTracks: true,
|
|
88
|
-
replaceIllegalCharacters: true,
|
|
89
|
-
colonReplacementFormat: 4, // 4 = Smart Replace (Dash or Space Dash depending on name)
|
|
90
|
-
// Standard track format: Artist - Album (Year) - Track# - Title
|
|
91
|
-
standardTrackFormat:
|
|
92
|
-
"{Artist CleanName} - {Album CleanTitle} ({Release Year}) - {track:00} - {Track CleanTitle}",
|
|
93
|
-
// Multi-disc format includes disc number
|
|
94
|
-
multiDiscTrackFormat:
|
|
95
|
-
"{Artist CleanName} - {Album CleanTitle} ({Release Year}) - {medium:00}-{track:00} - {Track CleanTitle}",
|
|
96
|
-
// Artist folder: Artist Name
|
|
97
|
-
artistFolderFormat: "{Artist CleanName}",
|
|
98
|
-
// Album folder: Album Title (Year) [Quality]
|
|
99
|
-
albumFolderFormat: "{Album CleanTitle} ({Release Year})",
|
|
100
|
-
} as LidarrNamingConfig,
|
|
101
|
-
}
|