@muhammedaksam/easiarr 1.4.0 → 1.6.0

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.
Files changed (109) hide show
  1. package/dist/index.js +29750 -0
  2. package/package.json +15 -15
  3. package/src/VersionInfo.ts +0 -12
  4. package/src/api/arr-api.ts +0 -521
  5. package/src/api/auto-setup-types.ts +0 -64
  6. package/src/api/base-api.ts +0 -216
  7. package/src/api/bazarr-api.ts +0 -297
  8. package/src/api/cloudflare-api.ts +0 -493
  9. package/src/api/custom-format-api.ts +0 -224
  10. package/src/api/grafana-api.ts +0 -230
  11. package/src/api/heimdall-api.ts +0 -141
  12. package/src/api/homarr-api.ts +0 -209
  13. package/src/api/huntarr-api.ts +0 -457
  14. package/src/api/index.ts +0 -9
  15. package/src/api/jellyfin-api.ts +0 -389
  16. package/src/api/jellyseerr-api.ts +0 -559
  17. package/src/api/maintainerr-api.ts +0 -461
  18. package/src/api/naming-config.ts +0 -101
  19. package/src/api/overseerr-api.ts +0 -392
  20. package/src/api/plex-api.ts +0 -308
  21. package/src/api/portainer-api.ts +0 -374
  22. package/src/api/profilarr-api.ts +0 -391
  23. package/src/api/prowlarr-api.ts +0 -488
  24. package/src/api/qbittorrent-api.ts +0 -300
  25. package/src/api/quality-profile-api.ts +0 -272
  26. package/src/api/tautulli-api.ts +0 -244
  27. package/src/api/uptime-kuma-api.ts +0 -343
  28. package/src/apps/categories.ts +0 -14
  29. package/src/apps/index.ts +0 -2
  30. package/src/apps/registry.ts +0 -1275
  31. package/src/compose/caddy-config.ts +0 -130
  32. package/src/compose/generator.ts +0 -287
  33. package/src/compose/index.ts +0 -7
  34. package/src/compose/templates.ts +0 -78
  35. package/src/compose/traefik-config.ts +0 -187
  36. package/src/config/bookmarks-generator.ts +0 -160
  37. package/src/config/defaults.ts +0 -37
  38. package/src/config/homepage-config.ts +0 -381
  39. package/src/config/index.ts +0 -6
  40. package/src/config/manager.ts +0 -150
  41. package/src/config/recyclarr-config.ts +0 -181
  42. package/src/config/schema.ts +0 -310
  43. package/src/config/slskd-config.ts +0 -86
  44. package/src/config/soularr-config.ts +0 -105
  45. package/src/config/trash-quality-definitions.ts +0 -213
  46. package/src/data/lidarr-custom-formats.ts +0 -127
  47. package/src/data/trash-profiles.ts +0 -333
  48. package/src/docker/client.ts +0 -312
  49. package/src/docker/index.ts +0 -18
  50. package/src/index.ts +0 -77
  51. package/src/setup/actions/arr-common.ts +0 -307
  52. package/src/setup/actions/dashboards.ts +0 -79
  53. package/src/setup/actions/download-clients.ts +0 -54
  54. package/src/setup/actions/jellyseerr.ts +0 -331
  55. package/src/setup/actions/media-servers.ts +0 -68
  56. package/src/setup/actions/monitoring.ts +0 -120
  57. package/src/setup/actions/prowlarr.ts +0 -137
  58. package/src/setup/actions/utilities.ts +0 -490
  59. package/src/setup/index.ts +0 -78
  60. package/src/setup/types.ts +0 -144
  61. package/src/structure/manager.ts +0 -129
  62. package/src/ui/App.ts +0 -111
  63. package/src/ui/components/ApplicationSelector.ts +0 -275
  64. package/src/ui/components/CredentialsForm.ts +0 -180
  65. package/src/ui/components/DownloadClientForm.ts +0 -114
  66. package/src/ui/components/FileEditor.ts +0 -91
  67. package/src/ui/components/FooterHint.ts +0 -119
  68. package/src/ui/components/PageLayout.ts +0 -160
  69. package/src/ui/components/UpdateNotification.ts +0 -102
  70. package/src/ui/index.ts +0 -7
  71. package/src/ui/screens/AdvancedSettings.ts +0 -188
  72. package/src/ui/screens/ApiKeyViewer.ts +0 -511
  73. package/src/ui/screens/AppConfigurator.ts +0 -543
  74. package/src/ui/screens/AppManager.ts +0 -284
  75. package/src/ui/screens/ContainerControl.ts +0 -581
  76. package/src/ui/screens/LogsViewer.ts +0 -478
  77. package/src/ui/screens/MainMenu.ts +0 -299
  78. package/src/ui/screens/MonitorDashboard.ts +0 -881
  79. package/src/ui/screens/SecretsEditor.ts +0 -216
  80. package/src/ui/screens/SettingsScreen.ts +0 -633
  81. package/src/ui/screens/index.ts +0 -22
  82. package/src/ui/screens/setup/BaseAppSetupScreen.ts +0 -375
  83. package/src/ui/screens/setup/CloudflaredSetup.ts +0 -460
  84. package/src/ui/screens/setup/FullAutoSetup.ts +0 -766
  85. package/src/ui/screens/setup/HomepageSetup.ts +0 -165
  86. package/src/ui/screens/setup/JellyfinSetup.ts +0 -328
  87. package/src/ui/screens/setup/JellyseerrSetup.ts +0 -242
  88. package/src/ui/screens/setup/ProwlarrSetup.ts +0 -500
  89. package/src/ui/screens/setup/QBittorrentSetup.ts +0 -221
  90. package/src/ui/screens/setup/QuickSetup.ts +0 -1169
  91. package/src/ui/screens/setup/RecyclarrSetup.ts +0 -270
  92. package/src/ui/screens/setup/TRaSHProfileSetup.ts +0 -381
  93. package/src/utils/arch.ts +0 -78
  94. package/src/utils/browser.ts +0 -27
  95. package/src/utils/categories.ts +0 -61
  96. package/src/utils/debug.ts +0 -84
  97. package/src/utils/env.ts +0 -138
  98. package/src/utils/index.ts +0 -8
  99. package/src/utils/logs.ts +0 -119
  100. package/src/utils/migrations/1765626338_rename_env_variables.ts +0 -102
  101. package/src/utils/migrations/1765707135_rename_easiarr_status.ts +0 -91
  102. package/src/utils/migrations/1765732722_remove_cloudflare_dns_api_token.ts +0 -45
  103. package/src/utils/migrations/1769515650_migrate_to_xdg.ts +0 -114
  104. package/src/utils/migrations.ts +0 -165
  105. package/src/utils/password.ts +0 -42
  106. package/src/utils/paths.ts +0 -33
  107. package/src/utils/unraid.ts +0 -103
  108. package/src/utils/update-checker.ts +0 -210
  109. package/src/utils/url-utils.ts +0 -38
@@ -1,300 +0,0 @@
1
- /**
2
- * qBittorrent WebAPI Client
3
- * Configures qBittorrent settings via API
4
- * API docs: https://github.com/qbittorrent/qBittorrent/wiki/WebUI-API-(qBittorrent-4.1)
5
- */
6
-
7
- import type { AutoSetupOptions, AutoSetupResult, IAutoSetupClient } from "./auto-setup-types"
8
- import { debugLog } from "~/utils/debug"
9
- import { BaseApiClient } from "./base-api"
10
-
11
- export interface QBittorrentPreferences {
12
- save_path?: string
13
- temp_path_enabled?: boolean
14
- temp_path?: string
15
- auto_tmm_enabled?: boolean
16
- category_changed_tmm_enabled?: boolean
17
- save_path_changed_tmm_enabled?: boolean
18
- max_ratio?: number
19
- max_ratio_enabled?: boolean
20
- max_ratio_act?: number
21
- max_seeding_time?: number
22
- max_seeding_time_enabled?: boolean
23
- queueing_enabled?: boolean
24
- web_ui_username?: string
25
- web_ui_password?: string
26
- listen_port?: number
27
- upnp?: boolean
28
- natpmp?: boolean
29
- dl_limit?: number
30
- up_limit?: number
31
- limit_utp_rate?: boolean
32
- limit_tcp_overhead?: boolean
33
- limit_lan_peers?: boolean
34
- enable_dht?: boolean
35
- enable_pex?: boolean
36
- enable_lsd?: boolean
37
- encryption_mode?: number
38
- anonymous_mode?: boolean
39
- add_trackers_enabled?: boolean
40
- pre_allocate_all?: boolean
41
- incomplete_files_ext?: boolean
42
- create_subfolder_enabled?: boolean
43
- }
44
-
45
- export interface QBittorrentCategory {
46
- name: string
47
- savePath: string
48
- }
49
-
50
- export class QBittorrentClient extends BaseApiClient implements IAutoSetupClient {
51
- protected readonly logPrefix = "qBittorrent"
52
- private username: string
53
- private password: string
54
- private cookie: string | null = null
55
-
56
- constructor(host: string, port: number, username: string, password: string) {
57
- super(host, port)
58
- this.username = username
59
- this.password = password
60
- }
61
-
62
- /**
63
- * Authenticate with qBittorrent WebUI
64
- */
65
- async login(): Promise<boolean> {
66
- try {
67
- debugLog("qBittorrent", `Logging in to ${this.baseUrl} as ${this.username}`)
68
- const response = await fetch(`${this.baseUrl}/api/v2/auth/login`, {
69
- method: "POST",
70
- headers: { "Content-Type": "application/x-www-form-urlencoded" },
71
- body: `username=${encodeURIComponent(this.username)}&password=${encodeURIComponent(this.password)}`,
72
- })
73
-
74
- if (!response.ok) {
75
- return false
76
- }
77
-
78
- const setCookie = response.headers.get("set-cookie")
79
- if (setCookie) {
80
- const match = setCookie.match(/SID=([^;]+)/)
81
- if (match) {
82
- this.cookie = `SID=${match[1]}`
83
- return true
84
- }
85
- }
86
-
87
- const text = await response.text()
88
- return text === "Ok."
89
- } catch {
90
- return false
91
- }
92
- }
93
-
94
- /**
95
- * Check if connected
96
- */
97
- async isConnected(): Promise<boolean> {
98
- try {
99
- const response = await fetch(`${this.baseUrl}/api/v2/app/version`, {
100
- headers: this.cookie ? { Cookie: this.cookie } : {},
101
- })
102
- return response.ok
103
- } catch {
104
- return false
105
- }
106
- }
107
-
108
- /**
109
- * Get current preferences
110
- */
111
- async getPreferences(): Promise<QBittorrentPreferences> {
112
- const response = await fetch(`${this.baseUrl}/api/v2/app/preferences`, {
113
- headers: this.cookie ? { Cookie: this.cookie } : {},
114
- })
115
-
116
- if (!response.ok) {
117
- throw new Error(`Failed to get preferences: ${response.status}`)
118
- }
119
-
120
- return response.json()
121
- }
122
-
123
- /**
124
- * Set preferences
125
- */
126
- async setPreferences(prefs: QBittorrentPreferences): Promise<void> {
127
- const response = await fetch(`${this.baseUrl}/api/v2/app/setPreferences`, {
128
- method: "POST",
129
- headers: {
130
- "Content-Type": "application/x-www-form-urlencoded",
131
- ...(this.cookie ? { Cookie: this.cookie } : {}),
132
- },
133
- body: `json=${encodeURIComponent(JSON.stringify(prefs))}`,
134
- })
135
-
136
- if (!response.ok) {
137
- throw new Error(`Failed to set preferences: ${response.status}`)
138
- }
139
- }
140
-
141
- /**
142
- * Get all categories
143
- */
144
- async getCategories(): Promise<Record<string, { name: string; savePath: string }>> {
145
- const response = await fetch(`${this.baseUrl}/api/v2/torrents/categories`, {
146
- headers: this.cookie ? { Cookie: this.cookie } : {},
147
- })
148
-
149
- if (!response.ok) {
150
- throw new Error(`Failed to get categories: ${response.status}`)
151
- }
152
-
153
- return response.json()
154
- }
155
-
156
- /**
157
- * Create a category
158
- */
159
- async createCategory(name: string, savePath: string): Promise<void> {
160
- const response = await fetch(`${this.baseUrl}/api/v2/torrents/createCategory`, {
161
- method: "POST",
162
- headers: {
163
- "Content-Type": "application/x-www-form-urlencoded",
164
- ...(this.cookie ? { Cookie: this.cookie } : {}),
165
- },
166
- body: `category=${encodeURIComponent(name)}&savePath=${encodeURIComponent(savePath)}`,
167
- })
168
-
169
- if (!response.ok && response.status !== 409) {
170
- throw new Error(`Failed to create category: ${response.status}`)
171
- }
172
- }
173
-
174
- /**
175
- * Edit a category's save path
176
- */
177
- async editCategory(name: string, savePath: string): Promise<void> {
178
- const response = await fetch(`${this.baseUrl}/api/v2/torrents/editCategory`, {
179
- method: "POST",
180
- headers: {
181
- "Content-Type": "application/x-www-form-urlencoded",
182
- ...(this.cookie ? { Cookie: this.cookie } : {}),
183
- },
184
- body: `category=${encodeURIComponent(name)}&savePath=${encodeURIComponent(savePath)}`,
185
- })
186
-
187
- if (!response.ok) {
188
- throw new Error(`Failed to edit category: ${response.status}`)
189
- }
190
- }
191
-
192
- /**
193
- * Configure qBittorrent for TRaSH Guide compliance
194
- */
195
- async configureTRaSHCompliant(
196
- categories: QBittorrentCategory[] = [],
197
- auth?: { user: string; pass: string }
198
- ): Promise<void> {
199
- debugLog("qBittorrent", "Configuring TRaSH-compliant settings")
200
-
201
- const prefs: Record<string, unknown> = {
202
- save_path: "/data/torrents",
203
- temp_path_enabled: false,
204
- auto_tmm_enabled: true,
205
- category_changed_tmm_enabled: true,
206
- save_path_changed_tmm_enabled: true,
207
- pre_allocate_all: false,
208
- incomplete_files_ext: true,
209
- create_subfolder_enabled: true,
210
- upnp: false,
211
- natpmp: false,
212
- dl_limit: -1,
213
- up_limit: -1,
214
- limit_utp_rate: true,
215
- limit_tcp_overhead: false,
216
- limit_lan_peers: true,
217
- enable_dht: true,
218
- enable_pex: true,
219
- enable_lsd: true,
220
- encryption_mode: 0,
221
- anonymous_mode: false,
222
- add_trackers_enabled: false,
223
- queueing_enabled: true,
224
- max_ratio: -1,
225
- max_ratio_enabled: false,
226
- max_seeding_time_enabled: false,
227
- max_ratio_act: 0,
228
- }
229
-
230
- if (auth) {
231
- prefs.web_ui_username = auth.user
232
- prefs.web_ui_password = auth.pass
233
- }
234
-
235
- await this.setPreferences(prefs)
236
-
237
- for (const cat of categories) {
238
- try {
239
- await this.createCategory(cat.name, cat.savePath)
240
- } catch {
241
- try {
242
- await this.editCategory(cat.name, cat.savePath)
243
- } catch {
244
- // Ignore
245
- }
246
- }
247
- }
248
- }
249
-
250
- /**
251
- * Check if qBittorrent is reachable
252
- */
253
- async isHealthy(): Promise<boolean> {
254
- try {
255
- const response = await fetch(`${this.baseUrl}/api/v2/app/version`)
256
- return response.ok || response.status === 403
257
- } catch {
258
- return false
259
- }
260
- }
261
-
262
- /**
263
- * Check if already configured
264
- */
265
- async isInitialized(): Promise<boolean> {
266
- return this.isConnected()
267
- }
268
-
269
- /**
270
- * Run the auto-setup process
271
- */
272
- async setup(options: AutoSetupOptions): Promise<AutoSetupResult> {
273
- const { username, password } = options
274
-
275
- try {
276
- const healthy = await this.isHealthy()
277
- if (!healthy) {
278
- return { success: false, message: "qBittorrent not reachable" }
279
- }
280
-
281
- this.username = username
282
- this.password = password
283
-
284
- const loggedIn = await this.login()
285
- if (!loggedIn) {
286
- return { success: false, message: "Login failed - check credentials" }
287
- }
288
-
289
- await this.configureTRaSHCompliant([], { user: username, pass: password })
290
-
291
- return {
292
- success: true,
293
- message: "Configured with TRaSH-compliant settings",
294
- data: { trashCompliant: true },
295
- }
296
- } catch (error) {
297
- return { success: false, message: `${error}` }
298
- }
299
- }
300
- }
@@ -1,272 +0,0 @@
1
- /**
2
- * Quality Profile API Client
3
- * Manages Quality Profiles and Custom Format scoring for Radarr/Sonarr/Lidarr
4
- */
5
-
6
- import {
7
- TRASH_LIDARR_QUALITY_DEFINITIONS,
8
- TRASH_RADARR_QUALITY_DEFINITIONS,
9
- TRASH_SONARR_QUALITY_DEFINITIONS,
10
- } from "~/config/trash-quality-definitions"
11
- import { debugLog } from "~/utils/debug"
12
-
13
- export interface QualityItem {
14
- id?: number
15
- name?: string
16
- quality?: {
17
- id: number
18
- name: string
19
- source: string
20
- resolution: number
21
- }
22
- items?: QualityItem[]
23
- allowed: boolean
24
- }
25
-
26
- export interface FormatItem {
27
- format: number
28
- name?: string
29
- score: number
30
- }
31
-
32
- export interface QualityProfile {
33
- id?: number
34
- name: string
35
- upgradeAllowed: boolean
36
- cutoff: number
37
- minFormatScore: number
38
- cutoffFormatScore: number
39
- formatItems: FormatItem[]
40
- language?: { id: number; name: string }
41
- items: QualityItem[]
42
- }
43
-
44
- export interface QualityDefinition {
45
- id: number
46
- quality: {
47
- id: number
48
- name: string
49
- source: string
50
- resolution: number
51
- }
52
- title: string
53
- weight: number
54
- minSize: number
55
- maxSize: number
56
- preferredSize: number
57
- }
58
-
59
- export class QualityProfileClient {
60
- private baseUrl: string
61
- private apiKey: string
62
- private apiVersion: string
63
-
64
- constructor(host: string, port: number, apiKey: string, apiVersion = "v3") {
65
- this.baseUrl = `http://${host}:${port}/api/${apiVersion}`
66
- this.apiKey = apiKey
67
- this.apiVersion = apiVersion
68
- }
69
-
70
- private async request<T>(endpoint: string, options: RequestInit = {}): Promise<T> {
71
- const url = `${this.baseUrl}${endpoint}`
72
- const headers: Record<string, string> = {
73
- "X-Api-Key": this.apiKey,
74
- "Content-Type": "application/json",
75
- ...((options.headers as Record<string, string>) || {}),
76
- }
77
-
78
- const response = await fetch(url, { ...options, headers })
79
-
80
- if (!response.ok) {
81
- throw new Error(`API request failed: ${response.status} ${response.statusText}`)
82
- }
83
-
84
- const text = await response.text()
85
- if (!text) return {} as T
86
- return JSON.parse(text) as T
87
- }
88
-
89
- // Quality Profile methods
90
- async getQualityProfiles(): Promise<QualityProfile[]> {
91
- return this.request<QualityProfile[]>("/qualityprofile")
92
- }
93
-
94
- async getQualityProfile(id: number): Promise<QualityProfile> {
95
- return this.request<QualityProfile>(`/qualityprofile/${id}`)
96
- }
97
-
98
- async createQualityProfile(profile: Omit<QualityProfile, "id">): Promise<QualityProfile> {
99
- return this.request<QualityProfile>("/qualityprofile", {
100
- method: "POST",
101
- body: JSON.stringify(profile),
102
- })
103
- }
104
-
105
- async updateQualityProfile(id: number, profile: QualityProfile): Promise<QualityProfile> {
106
- return this.request<QualityProfile>(`/qualityprofile/${id}`, {
107
- method: "PUT",
108
- body: JSON.stringify({ ...profile, id }),
109
- })
110
- }
111
-
112
- async deleteQualityProfile(id: number): Promise<void> {
113
- await this.request(`/qualityprofile/${id}`, { method: "DELETE" })
114
- }
115
-
116
- // Quality Definition methods (for size limits)
117
- async getQualityDefinitions(): Promise<QualityDefinition[]> {
118
- return this.request<QualityDefinition[]>("/qualitydefinition")
119
- }
120
-
121
- async updateQualityDefinitions(definitions: QualityDefinition[]): Promise<QualityDefinition[]> {
122
- const updated: QualityDefinition[] = []
123
-
124
- // Update each definition individually as bulk update is not reliably supported across all versions
125
- for (const def of definitions) {
126
- if (!def.id) continue
127
-
128
- try {
129
- const result = await this.request<QualityDefinition>(`/qualitydefinition/${def.id}`, {
130
- method: "PUT",
131
- body: JSON.stringify(def),
132
- })
133
- updated.push(result)
134
- } catch (e) {
135
- debugLog("QualityProfile", `Failed to update definition ${def.id}: ${e}`)
136
- }
137
- }
138
- return updated
139
- }
140
-
141
- // Helper: Get quality by name from existing profiles
142
- async getQualityIdByName(name: string): Promise<number | null> {
143
- const profiles = await this.getQualityProfiles()
144
- if (profiles.length === 0) return null
145
-
146
- const findQuality = (items: QualityItem[]): number | null => {
147
- for (const item of items) {
148
- if (item.quality?.name === name) return item.quality.id
149
- if (item.items) {
150
- const found = findQuality(item.items)
151
- if (found !== null) return found
152
- }
153
- }
154
- return null
155
- }
156
-
157
- return findQuality(profiles[0].items)
158
- }
159
-
160
- // Create TRaSH-recommended profile
161
- async createTRaSHProfile(
162
- name: string,
163
- cutoffQualityName: string,
164
- allowedQualities: string[],
165
- cfScores: Record<string, number> = {}
166
- ): Promise<QualityProfile> {
167
- // Get existing profile to clone quality structure
168
- const existingProfiles = await this.getQualityProfiles()
169
- if (existingProfiles.length === 0) {
170
- throw new Error("No existing profiles to clone quality structure from")
171
- }
172
-
173
- const baseProfile = existingProfiles[0]
174
- const cutoffId = await this.getQualityIdByName(cutoffQualityName)
175
-
176
- if (cutoffId === null) {
177
- throw new Error(`Quality "${cutoffQualityName}" not found`)
178
- }
179
-
180
- // Build quality items with allowed flags
181
- const setAllowed = (items: QualityItem[]): QualityItem[] => {
182
- return items.map((item) => {
183
- if (item.items) {
184
- return { ...item, items: setAllowed(item.items) }
185
- }
186
- return {
187
- ...item,
188
- allowed: item.quality ? allowedQualities.includes(item.quality.name) : false,
189
- }
190
- })
191
- }
192
-
193
- // Get custom formats and map scores
194
- const formatItems: FormatItem[] = baseProfile.formatItems.map((fi) => ({
195
- format: fi.format,
196
- name: fi.name,
197
- score: cfScores[fi.name || ""] ?? 0,
198
- }))
199
-
200
- const newProfile: Omit<QualityProfile, "id"> = {
201
- name,
202
- upgradeAllowed: true,
203
- cutoff: cutoffId,
204
- minFormatScore: 0,
205
- cutoffFormatScore: 10000,
206
- formatItems,
207
- language: baseProfile.language,
208
- items: setAllowed(baseProfile.items),
209
- }
210
-
211
- return this.createQualityProfile(newProfile)
212
- }
213
-
214
- // Update CF scores on existing profile
215
- async updateProfileCFScores(
216
- profileId: number,
217
- cfScores: Record<string, number>
218
- ): Promise<QualityProfile> {
219
- const profile = await this.getQualityProfile(profileId)
220
-
221
- profile.formatItems = profile.formatItems.map((fi) => ({
222
- ...fi,
223
- score: cfScores[fi.name || ""] ?? fi.score,
224
- }))
225
-
226
- return this.updateQualityProfile(profileId, profile)
227
- }
228
-
229
- // Apply TRaSH/Davo Quality Definitions (File Size Limits)
230
- async updateTrashQualityDefinitions(appType: "radarr" | "sonarr" | "lidarr"): Promise<void> {
231
- try {
232
- debugLog("QualityProfile", `Updating Quality Definitions for ${appType}`)
233
- const definitions = await this.getQualityDefinitions()
234
-
235
- // Get appropriate definitions based on app type
236
- let trashDefs
237
- if (appType === "radarr") {
238
- trashDefs = TRASH_RADARR_QUALITY_DEFINITIONS
239
- } else if (appType === "sonarr") {
240
- trashDefs = TRASH_SONARR_QUALITY_DEFINITIONS
241
- } else {
242
- trashDefs = TRASH_LIDARR_QUALITY_DEFINITIONS
243
- }
244
-
245
- let updatedCount = 0
246
-
247
- const newDefinitions = definitions.map((def) => {
248
- const trashDef = trashDefs.find((t) => t.quality === def.quality.name)
249
- if (trashDef) {
250
- updatedCount++
251
- return {
252
- ...def,
253
- minSize: trashDef.min,
254
- maxSize: trashDef.max,
255
- preferredSize: trashDef.preferred,
256
- }
257
- }
258
- return def
259
- })
260
-
261
- if (updatedCount > 0) {
262
- await this.updateQualityDefinitions(newDefinitions)
263
- debugLog("QualityProfile", `Successfully updated ${updatedCount} quality definitions`)
264
- } else {
265
- debugLog("QualityProfile", "No matching quality definitions found to update")
266
- }
267
- } catch (e) {
268
- debugLog("QualityProfile", `Failed to update quality definitions: ${e}`)
269
- throw e
270
- }
271
- }
272
- }