@muhammedaksam/easiarr 1.1.1 → 1.1.3

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.
@@ -7,9 +7,11 @@ import { BoxRenderable, CliRenderer, TextRenderable, KeyEvent } from "@opentui/c
7
7
  import { createPageLayout } from "../components/PageLayout"
8
8
  import { EasiarrConfig, AppId } from "../../config/schema"
9
9
  import { getApp } from "../../apps/registry"
10
+ import { ArrApiClient } from "../../api/arr-api"
10
11
  import { QualityProfileClient } from "../../api/quality-profile-api"
11
12
  import { CustomFormatClient, getCFNamesForCategories } from "../../api/custom-format-api"
12
13
  import { getPresetsForApp, TRaSHProfilePreset } from "../../data/trash-profiles"
14
+ import { LIDARR_CUSTOM_FORMATS } from "../../data/lidarr-custom-formats"
13
15
  import { readEnvSync } from "../../utils/env"
14
16
  import { debugLog } from "../../utils/debug"
15
17
 
@@ -18,6 +20,7 @@ interface SetupResult {
18
20
  appName: string
19
21
  profile: string
20
22
  cfCount: number
23
+ namingConfigured: boolean
21
24
  status: "pending" | "configuring" | "success" | "error"
22
25
  message?: string
23
26
  }
@@ -61,12 +64,14 @@ export class TRaSHProfileSetup extends BoxRenderable {
61
64
  this.pageContainer = pageContainer
62
65
 
63
66
  // Get enabled *arr apps that support quality profiles
64
- this.availableApps = config.apps.filter((a) => a.enabled && ["radarr", "sonarr"].includes(a.id)).map((a) => a.id)
67
+ this.availableApps = config.apps
68
+ .filter((a) => a.enabled && ["radarr", "sonarr", "lidarr"].includes(a.id))
69
+ .map((a) => a.id)
65
70
 
66
71
  // Initialize selections
67
72
  this.availableApps.forEach((id) => {
68
73
  this.selectedApps.set(id, true)
69
- const presets = getPresetsForApp(id as "radarr" | "sonarr")
74
+ const presets = getPresetsForApp(id as "radarr" | "sonarr" | "lidarr")
70
75
  if (presets.length > 0) {
71
76
  this.selectedProfiles.set(id, presets[0].id)
72
77
  }
@@ -134,7 +139,7 @@ export class TRaSHProfileSetup extends BoxRenderable {
134
139
  private handleSelectProfilesKeys(key: KeyEvent): void {
135
140
  const selectedAppIds = this.availableApps.filter((id) => this.selectedApps.get(id))
136
141
  const app = selectedAppIds[this.currentIndex]
137
- const presets = getPresetsForApp(app as "radarr" | "sonarr")
142
+ const presets = getPresetsForApp(app as "radarr" | "sonarr" | "lidarr")
138
143
 
139
144
  if (key.name === "up") {
140
145
  const current = this.selectedProfiles.get(app)
@@ -176,7 +181,7 @@ export class TRaSHProfileSetup extends BoxRenderable {
176
181
  for (const appId of selectedAppIds) {
177
182
  const appDef = getApp(appId)
178
183
  const profileId = this.selectedProfiles.get(appId)
179
- const preset = getPresetsForApp(appId as "radarr" | "sonarr").find((p) => p.id === profileId)
184
+ const preset = getPresetsForApp(appId as "radarr" | "sonarr" | "lidarr").find((p) => p.id === profileId)
180
185
 
181
186
  if (!appDef || !preset) continue
182
187
 
@@ -185,6 +190,7 @@ export class TRaSHProfileSetup extends BoxRenderable {
185
190
  appName: appDef.name,
186
191
  profile: preset.name,
187
192
  cfCount: 0,
193
+ namingConfigured: false,
188
194
  status: "configuring",
189
195
  })
190
196
  this.refreshContent()
@@ -195,6 +201,7 @@ export class TRaSHProfileSetup extends BoxRenderable {
195
201
  if (result) {
196
202
  result.status = "success"
197
203
  result.cfCount = Object.keys(preset.cfScores).length
204
+ result.namingConfigured = true
198
205
  }
199
206
  } catch (error) {
200
207
  const result = this.results.find((r) => r.appId === appId)
@@ -219,24 +226,36 @@ export class TRaSHProfileSetup extends BoxRenderable {
219
226
  if (!apiKey) throw new Error("API key not found - run Extract API Keys first")
220
227
 
221
228
  const port = this.config.apps.find((a) => a.id === appId)?.port || appDef.defaultPort
222
- const qpClient = new QualityProfileClient("localhost", port, apiKey)
223
- const cfClient = new CustomFormatClient("localhost", port, apiKey)
224
-
225
- // Import Custom Formats first
226
- const cfCategories = ["unwanted", "misc"]
227
- if (preset.id.includes("uhd") || preset.id.includes("2160")) {
228
- cfCategories.push("hdr")
229
- }
230
- if (preset.id.includes("remux")) {
231
- cfCategories.push("audio")
229
+ const apiVersion = appDef.rootFolder?.apiVersion || "v3"
230
+ const qpClient = new QualityProfileClient("localhost", port, apiKey, apiVersion)
231
+ const cfClient = new CustomFormatClient("localhost", port, apiKey, apiVersion)
232
+
233
+ // Import Custom Formats - Lidarr uses Davo's guide formats, Radarr/Sonarr use TRaSH
234
+ if (appId === "lidarr") {
235
+ // Import Lidarr custom formats from Davo's Community Guide
236
+ await cfClient.importCustomFormats(LIDARR_CUSTOM_FORMATS)
237
+ } else {
238
+ // Import TRaSH custom formats for Radarr/Sonarr
239
+ const cfCategories = ["unwanted", "misc"]
240
+ if (preset.id.includes("uhd") || preset.id.includes("2160")) {
241
+ cfCategories.push("hdr")
242
+ }
243
+ if (preset.id.includes("remux")) {
244
+ cfCategories.push("audio")
245
+ }
246
+ const cfNames = getCFNamesForCategories(appId as "radarr" | "sonarr", cfCategories)
247
+ const { cfs } = await CustomFormatClient.fetchTRaSHCustomFormats(appId as "radarr" | "sonarr", cfNames)
248
+ await cfClient.importCustomFormats(cfs)
232
249
  }
233
250
 
234
- const cfNames = getCFNamesForCategories(appId as "radarr" | "sonarr", cfCategories)
235
- const { cfs } = await CustomFormatClient.fetchTRaSHCustomFormats(appId as "radarr" | "sonarr", cfNames)
236
- await cfClient.importCustomFormats(cfs)
237
-
238
251
  // Create quality profile
239
252
  await qpClient.createTRaSHProfile(preset.name, preset.cutoffQuality, preset.allowedQualities, preset.cfScores)
253
+
254
+ // Configure naming scheme (skip for Lidarr - different API structure)
255
+ if (appId !== "lidarr") {
256
+ const arrClient = new ArrApiClient("localhost", port, apiKey, apiVersion)
257
+ await arrClient.configureTRaSHNaming(appId as "radarr" | "sonarr")
258
+ }
240
259
  }
241
260
 
242
261
  private refreshContent(): void {
@@ -293,7 +312,7 @@ export class TRaSHProfileSetup extends BoxRenderable {
293
312
 
294
313
  selectedAppIds.forEach((appId, appIdx) => {
295
314
  const app = getApp(appId)
296
- const presets = getPresetsForApp(appId as "radarr" | "sonarr")
315
+ const presets = getPresetsForApp(appId as "radarr" | "sonarr" | "lidarr")
297
316
  const selectedPresetId = this.selectedProfiles.get(appId)
298
317
  const isCurrent = appIdx === this.currentIndex
299
318
 
@@ -349,7 +368,7 @@ export class TRaSHProfileSetup extends BoxRenderable {
349
368
 
350
369
  let content = `${status} ${result.appName}: ${result.profile}`
351
370
  if (result.status === "success") {
352
- content += ` (${result.cfCount} CF scores)`
371
+ content += ` (${result.cfCount} CF scores, naming configured)`
353
372
  }
354
373
  if (result.message) {
355
374
  content += ` - ${result.message}`
@@ -0,0 +1,38 @@
1
+ /**
2
+ * URL Utilities
3
+ * Functions for generating app URLs based on Traefik configuration
4
+ */
5
+
6
+ import type { EasiarrConfig } from "../config/schema"
7
+ import { getLocalIp } from "./env"
8
+
9
+ /**
10
+ * Get the local URL for an app (http://LOCAL_IP:PORT)
11
+ */
12
+ export function getLocalAppUrl(port: number): string {
13
+ const localIp = getLocalIp()
14
+ return `http://${localIp}:${port}`
15
+ }
16
+
17
+ /**
18
+ * Get the external URL for an app (https://APP.DOMAIN)
19
+ * Returns null if Traefik is not enabled
20
+ */
21
+ export function getExternalAppUrl(appId: string, config: EasiarrConfig): string | null {
22
+ if (!config.traefik?.enabled || !config.traefik.domain) {
23
+ return null
24
+ }
25
+ return `https://${appId}.${config.traefik.domain}`
26
+ }
27
+
28
+ /**
29
+ * Get the appropriate applicationUrl based on Traefik status
30
+ * Returns external URL if Traefik enabled, otherwise local URL
31
+ */
32
+ export function getApplicationUrl(appId: string, port: number, config: EasiarrConfig): string {
33
+ const externalUrl = getExternalAppUrl(appId, config)
34
+ if (externalUrl) {
35
+ return externalUrl
36
+ }
37
+ return getLocalAppUrl(port)
38
+ }