@muhammedaksam/easiarr 0.1.1 → 0.1.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@muhammedaksam/easiarr",
3
- "version": "0.1.1",
3
+ "version": "0.1.4",
4
4
  "description": "TUI tool for generating docker-compose files for the *arr media ecosystem with 41 apps, TRaSH Guides best practices, VPN routing, and Traefik reverse proxy support",
5
5
  "module": "src/index.ts",
6
6
  "type": "module",
@@ -94,6 +94,10 @@ export const APPS: Record<AppId, AppDefinition> = {
94
94
  path: "/data/media/books",
95
95
  apiVersion: "v1",
96
96
  },
97
+ arch: {
98
+ deprecated: ["arm64", "arm32"],
99
+ warning: "Readarr is deprecated - no ARM64 support (project abandoned by upstream)",
100
+ },
97
101
  },
98
102
 
99
103
  bazarr: {
@@ -866,3 +870,32 @@ export function getAllApps(): AppDefinition[] {
866
870
  export function getAppIds(): AppId[] {
867
871
  return Object.keys(APPS) as AppId[]
868
872
  }
873
+
874
+ import { getSystemArch, isAppCompatible, getArchWarning, isAppDeprecated } from "../util/arch"
875
+
876
+ /**
877
+ * Get all apps compatible with the current system architecture
878
+ */
879
+ export function getCompatibleApps(): AppDefinition[] {
880
+ const arch = getSystemArch()
881
+ return Object.values(APPS).filter((app) => isAppCompatible(app, arch))
882
+ }
883
+
884
+ /**
885
+ * Get apps that have warnings for the current architecture (deprecated but may work)
886
+ */
887
+ export function getAppsWithArchWarnings(): { app: AppDefinition; warning: string }[] {
888
+ const arch = getSystemArch()
889
+ const result: { app: AppDefinition; warning: string }[] = []
890
+
891
+ for (const app of Object.values(APPS)) {
892
+ const warning = getArchWarning(app, arch)
893
+ if (warning) {
894
+ result.push({ app, warning })
895
+ }
896
+ }
897
+
898
+ return result
899
+ }
900
+
901
+ export { getSystemArch, isAppCompatible, getArchWarning, isAppDeprecated }
@@ -123,6 +123,17 @@ export type AppCategory =
123
123
  | "monitoring"
124
124
  | "infrastructure"
125
125
 
126
+ export type Architecture = "x64" | "arm64" | "arm32"
127
+
128
+ export interface ArchCompatibility {
129
+ /** Architectures with full support */
130
+ supported?: Architecture[]
131
+ /** Architectures with deprecated/broken support - will show warning */
132
+ deprecated?: Architecture[]
133
+ /** Warning message to show for deprecated architectures */
134
+ warning?: string
135
+ }
136
+
126
137
  export interface AppDefinition {
127
138
  id: AppId
128
139
  name: string
@@ -141,6 +152,8 @@ export interface AppDefinition {
141
152
  cap_add?: string[]
142
153
  apiKeyMeta?: ApiKeyMeta
143
154
  rootFolder?: RootFolderMeta
155
+ /** Architecture compatibility info - omit if supports all */
156
+ arch?: ArchCompatibility
144
157
  }
145
158
 
146
159
  export interface RootFolderMeta {
@@ -11,7 +11,7 @@ import {
11
11
  } from "@opentui/core"
12
12
  import { AppId } from "../../config/schema"
13
13
  import { CATEGORY_ORDER } from "../../apps/categories"
14
- import { getAppsByCategory } from "../../apps"
14
+ import { getAppsByCategory, getArchWarning } from "../../apps"
15
15
 
16
16
  export interface ApplicationSelectorOptions extends BoxOptions {
17
17
  selectedApps: Set<AppId>
@@ -139,10 +139,15 @@ export class ApplicationSelector extends BoxRenderable {
139
139
  const category = CATEGORY_ORDER[this.currentCategoryIndex]
140
140
  const apps = getAppsByCategory()[category.id] || []
141
141
 
142
- const options = apps.map((app) => ({
143
- name: `${this.selectedApps.has(app.id) ? "[✓]" : "[ ]"} ${app.name}`,
144
- description: `Port ${app.defaultPort} - ${app.description}`,
145
- }))
142
+ const options = apps.map((app) => {
143
+ const archWarning = getArchWarning(app)
144
+ const checkmark = this.selectedApps.has(app.id) ? "[✓]" : "[ ]"
145
+ const warnIcon = archWarning ? " ⚠️" : ""
146
+ return {
147
+ name: `${checkmark} ${app.name}${warnIcon}`,
148
+ description: archWarning ? `⚠️ ${archWarning}` : `Port ${app.defaultPort} - ${app.description}`,
149
+ }
150
+ })
146
151
 
147
152
  this.appList.options = options
148
153
  }
@@ -177,6 +182,17 @@ export class ApplicationSelector extends BoxRenderable {
177
182
  check(["overseerr", "jellyseerr"], "Multiple request managers")
178
183
  check(["prowlarr", "jackett"], "Multiple indexers")
179
184
 
185
+ // Architecture warnings for selected apps
186
+ const allApps = Object.values(getAppsByCategory()).flat()
187
+ for (const app of allApps) {
188
+ if (this.selectedApps.has(app.id)) {
189
+ const archWarn = getArchWarning(app)
190
+ if (archWarn) {
191
+ warnings.push(archWarn)
192
+ }
193
+ }
194
+ }
195
+
180
196
  return warnings
181
197
  }
182
198
 
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Architecture Detection Utility
3
+ * Detects system architecture and checks app compatibility
4
+ */
5
+
6
+ import type { AppDefinition, Architecture } from "../config/schema"
7
+
8
+ /**
9
+ * Get the current system architecture
10
+ */
11
+ export function getSystemArch(): Architecture {
12
+ const arch = process.arch
13
+ switch (arch) {
14
+ case "x64":
15
+ case "ia32":
16
+ return "x64"
17
+ case "arm64":
18
+ return "arm64"
19
+ case "arm":
20
+ return "arm32"
21
+ default:
22
+ return "x64" // Default to x64 for unknown
23
+ }
24
+ }
25
+
26
+ /**
27
+ * Check if an app is compatible with the given architecture
28
+ * Returns true if compatible (no issues), false if deprecated/broken
29
+ */
30
+ export function isAppCompatible(app: AppDefinition, arch?: Architecture): boolean {
31
+ const systemArch = arch ?? getSystemArch()
32
+
33
+ if (!app.arch) {
34
+ return true // No arch restrictions = supports all
35
+ }
36
+
37
+ // Check if explicitly deprecated
38
+ if (app.arch.deprecated?.includes(systemArch)) {
39
+ return false
40
+ }
41
+
42
+ // If supported list exists, check if current arch is in it
43
+ if (app.arch.supported && !app.arch.supported.includes(systemArch)) {
44
+ return false
45
+ }
46
+
47
+ return true
48
+ }
49
+
50
+ /**
51
+ * Get warning message for an app on the current architecture
52
+ * Returns null if no warning
53
+ */
54
+ export function getArchWarning(app: AppDefinition, arch?: Architecture): string | null {
55
+ const systemArch = arch ?? getSystemArch()
56
+
57
+ if (!app.arch) {
58
+ return null
59
+ }
60
+
61
+ if (app.arch.deprecated?.includes(systemArch)) {
62
+ return app.arch.warning || `${app.name} has deprecated support for ${systemArch}`
63
+ }
64
+
65
+ if (app.arch.supported && !app.arch.supported.includes(systemArch)) {
66
+ return `${app.name} does not support ${systemArch} architecture`
67
+ }
68
+
69
+ return null
70
+ }
71
+
72
+ /**
73
+ * Check if app is deprecated (but might still work)
74
+ */
75
+ export function isAppDeprecated(app: AppDefinition, arch?: Architecture): boolean {
76
+ const systemArch = arch ?? getSystemArch()
77
+ return app.arch?.deprecated?.includes(systemArch) ?? false
78
+ }