@muhammedaksam/easiarr 1.1.4 → 1.1.6
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": "1.1.
|
|
3
|
+
"version": "1.1.6",
|
|
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",
|
package/src/api/prowlarr-api.ts
CHANGED
|
@@ -240,11 +240,11 @@ export class ProwlarrClient implements IAutoSetupClient {
|
|
|
240
240
|
|
|
241
241
|
// Sync Profile management (aka App Sync Profile)
|
|
242
242
|
async getSyncProfiles(): Promise<SyncProfile[]> {
|
|
243
|
-
return this.request<SyncProfile[]>("/
|
|
243
|
+
return this.request<SyncProfile[]>("/appprofile")
|
|
244
244
|
}
|
|
245
245
|
|
|
246
246
|
async createSyncProfile(profile: Omit<SyncProfile, "id">): Promise<SyncProfile> {
|
|
247
|
-
return this.request<SyncProfile>("/
|
|
247
|
+
return this.request<SyncProfile>("/appprofile", {
|
|
248
248
|
method: "POST",
|
|
249
249
|
body: JSON.stringify(profile),
|
|
250
250
|
})
|
|
@@ -335,15 +335,55 @@ export class ProwlarrClient implements IAutoSetupClient {
|
|
|
335
335
|
await this.request(`/applications/${id}`, { method: "DELETE" })
|
|
336
336
|
}
|
|
337
337
|
|
|
338
|
+
// Update an existing application
|
|
339
|
+
async updateApplication(
|
|
340
|
+
id: number,
|
|
341
|
+
appType: ArrAppType,
|
|
342
|
+
name: string,
|
|
343
|
+
prowlarrUrl: string,
|
|
344
|
+
appUrl: string,
|
|
345
|
+
appApiKey: string,
|
|
346
|
+
syncLevel: "disabled" | "addOnly" | "fullSync" = "fullSync",
|
|
347
|
+
syncCategories: number[] = [],
|
|
348
|
+
tags: number[] = []
|
|
349
|
+
): Promise<Application> {
|
|
350
|
+
const fields: { name: string; value: unknown }[] = [
|
|
351
|
+
{ name: "prowlarrUrl", value: prowlarrUrl },
|
|
352
|
+
{ name: "baseUrl", value: appUrl },
|
|
353
|
+
{ name: "apiKey", value: appApiKey },
|
|
354
|
+
{ name: "syncCategories", value: syncCategories },
|
|
355
|
+
{ name: "syncRejectBlocklistedTorrentHashesWhileGrabbing", value: false },
|
|
356
|
+
]
|
|
357
|
+
|
|
358
|
+
return this.request<Application>(`/applications/${id}`, {
|
|
359
|
+
method: "PUT",
|
|
360
|
+
body: JSON.stringify({
|
|
361
|
+
id,
|
|
362
|
+
name,
|
|
363
|
+
syncLevel,
|
|
364
|
+
enable: true,
|
|
365
|
+
implementation: appType,
|
|
366
|
+
implementationName: appType,
|
|
367
|
+
configContract: `${appType}Settings`,
|
|
368
|
+
infoLink: `https://wiki.servarr.com/prowlarr/supported#${appType.toLowerCase()}`,
|
|
369
|
+
fields,
|
|
370
|
+
tags,
|
|
371
|
+
}),
|
|
372
|
+
})
|
|
373
|
+
}
|
|
374
|
+
|
|
338
375
|
// Sync all apps - triggers Prowlarr to push indexers to connected apps
|
|
339
376
|
async syncApplications(): Promise<void> {
|
|
340
|
-
await this.request("/
|
|
377
|
+
await this.request("/command", {
|
|
341
378
|
method: "POST",
|
|
342
|
-
body: JSON.stringify({
|
|
379
|
+
body: JSON.stringify({
|
|
380
|
+
name: "ApplicationIndexerSync",
|
|
381
|
+
forceSync: true,
|
|
382
|
+
}),
|
|
343
383
|
})
|
|
344
384
|
}
|
|
345
385
|
|
|
346
|
-
// Add *arr app
|
|
386
|
+
// Add or update *arr app
|
|
347
387
|
async addArrApp(
|
|
348
388
|
appType: ArrAppType,
|
|
349
389
|
host: string,
|
|
@@ -359,10 +399,27 @@ export class ProwlarrClient implements IAutoSetupClient {
|
|
|
359
399
|
// Check if app already exists
|
|
360
400
|
const apps = await this.getApplications()
|
|
361
401
|
const existing = apps.find((a) => a.implementation === appType)
|
|
362
|
-
|
|
363
|
-
|
|
402
|
+
|
|
403
|
+
if (existing && existing.id) {
|
|
404
|
+
// Update existing app with new syncCategories
|
|
405
|
+
debugLog(
|
|
406
|
+
"Prowlarr",
|
|
407
|
+
`Updating existing ${appType} app (id=${existing.id}) with syncCategories: ${JSON.stringify(syncCategories)}`
|
|
408
|
+
)
|
|
409
|
+
return this.updateApplication(
|
|
410
|
+
existing.id,
|
|
411
|
+
appType,
|
|
412
|
+
existing.name,
|
|
413
|
+
prowlarrUrl,
|
|
414
|
+
appUrl,
|
|
415
|
+
apiKey,
|
|
416
|
+
"fullSync",
|
|
417
|
+
syncCategories || [],
|
|
418
|
+
existing.tags || []
|
|
419
|
+
)
|
|
364
420
|
}
|
|
365
421
|
|
|
422
|
+
// Create new app
|
|
366
423
|
return this.addApplication(appType, appType, prowlarrUrl, appUrl, apiKey, "fullSync", syncCategories)
|
|
367
424
|
}
|
|
368
425
|
|
package/src/apps/registry.ts
CHANGED
|
@@ -29,7 +29,7 @@ export const APPS: Record<AppId, AppDefinition> = {
|
|
|
29
29
|
path: "/data/media/movies",
|
|
30
30
|
apiVersion: "v3",
|
|
31
31
|
},
|
|
32
|
-
prowlarrCategoryIds: [2000], // Movies
|
|
32
|
+
prowlarrCategoryIds: [2000, 2010, 2020, 2030, 2040, 2045, 2050, 2060, 2070, 2080, 2090], // Movies + all sub-categories
|
|
33
33
|
homepage: { icon: "radarr.png", widget: "radarr" },
|
|
34
34
|
},
|
|
35
35
|
|
|
@@ -54,7 +54,7 @@ export const APPS: Record<AppId, AppDefinition> = {
|
|
|
54
54
|
path: "/data/media/tv",
|
|
55
55
|
apiVersion: "v3",
|
|
56
56
|
},
|
|
57
|
-
prowlarrCategoryIds: [5000], // TV
|
|
57
|
+
prowlarrCategoryIds: [5000, 5010, 5020, 5030, 5040, 5045, 5050, 5060, 5070, 5080, 5090], // TV + all sub-categories
|
|
58
58
|
homepage: { icon: "sonarr.png", widget: "sonarr" },
|
|
59
59
|
},
|
|
60
60
|
|
|
@@ -77,7 +77,7 @@ export const APPS: Record<AppId, AppDefinition> = {
|
|
|
77
77
|
path: "/data/media/music",
|
|
78
78
|
apiVersion: "v1",
|
|
79
79
|
},
|
|
80
|
-
prowlarrCategoryIds: [3000], // Audio
|
|
80
|
+
prowlarrCategoryIds: [3000, 3010, 3020, 3030, 3040, 3050, 3060], // Audio + all sub-categories
|
|
81
81
|
homepage: { icon: "lidarr.png", widget: "lidarr" },
|
|
82
82
|
},
|
|
83
83
|
|
|
@@ -100,7 +100,7 @@ export const APPS: Record<AppId, AppDefinition> = {
|
|
|
100
100
|
path: "/data/media/books",
|
|
101
101
|
apiVersion: "v1",
|
|
102
102
|
},
|
|
103
|
-
prowlarrCategoryIds: [7000], // Books
|
|
103
|
+
prowlarrCategoryIds: [7000, 7010, 7020, 7030, 7040, 7050, 7060], // Books + all sub-categories
|
|
104
104
|
arch: {
|
|
105
105
|
deprecated: ["arm64", "arm32"],
|
|
106
106
|
warning: "Readarr is deprecated - no ARM64 support (project abandoned by upstream)",
|
|
@@ -172,7 +172,7 @@ export const APPS: Record<AppId, AppDefinition> = {
|
|
|
172
172
|
path: "/data/media/adult",
|
|
173
173
|
apiVersion: "v3",
|
|
174
174
|
},
|
|
175
|
-
prowlarrCategoryIds: [6000], // XXX
|
|
175
|
+
prowlarrCategoryIds: [6000, 6010, 6020, 6030, 6040, 6045, 6050, 6060, 6070, 6080, 6090], // XXX + all sub-categories
|
|
176
176
|
homepage: { icon: "whisparr.png", widget: "sonarr" }, // Uses sonarr widget type
|
|
177
177
|
},
|
|
178
178
|
|
|
@@ -320,8 +320,9 @@ export const APPS: Record<AppId, AppDefinition> = {
|
|
|
320
320
|
category: "downloader",
|
|
321
321
|
defaultPort: 5030,
|
|
322
322
|
image: "slskd/slskd",
|
|
323
|
-
puid:
|
|
324
|
-
pgid:
|
|
323
|
+
puid: 0, // Uses Docker user: directive instead
|
|
324
|
+
pgid: 0,
|
|
325
|
+
useDockerUser: true, // Use Docker's user: directive for file permissions
|
|
325
326
|
volumes: (root) => [`${root}/config/slskd:/app`, `${root}/data:/data`],
|
|
326
327
|
secondaryPorts: ["5031:5031", "50300:50300"],
|
|
327
328
|
environment: {
|
package/src/compose/generator.ts
CHANGED
|
@@ -25,6 +25,8 @@ export interface ComposeService {
|
|
|
25
25
|
devices?: string[]
|
|
26
26
|
cap_add?: string[]
|
|
27
27
|
command?: string
|
|
28
|
+
/** Docker user directive (e.g., "1000:1000") for apps that don't support PUID/PGID */
|
|
29
|
+
user?: string
|
|
28
30
|
}
|
|
29
31
|
|
|
30
32
|
export interface ComposeFile {
|
|
@@ -157,6 +159,15 @@ function buildService(appDef: ReturnType<typeof getApp>, appConfig: AppConfig, c
|
|
|
157
159
|
// Add command (e.g., cloudflared)
|
|
158
160
|
if (appDef.command) service.command = appDef.command
|
|
159
161
|
|
|
162
|
+
// Use Docker user directive for apps that don't support PUID/PGID (e.g., slskd)
|
|
163
|
+
if (appDef.useDockerUser) {
|
|
164
|
+
service.user = "${PUID}:${PGID}"
|
|
165
|
+
// Remove PUID/PGID env vars since they're not used
|
|
166
|
+
delete service.environment.PUID
|
|
167
|
+
delete service.environment.PGID
|
|
168
|
+
delete service.environment.UMASK
|
|
169
|
+
}
|
|
170
|
+
|
|
160
171
|
// Plex uses network_mode: host
|
|
161
172
|
if (appDef.id === "plex") {
|
|
162
173
|
service.network_mode = "host"
|
package/src/compose/templates.ts
CHANGED
|
@@ -60,6 +60,11 @@ export function generateServiceYaml(name: string, service: ComposeService): stri
|
|
|
60
60
|
}
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
+
// User directive (for apps like slskd that don't support PUID/PGID)
|
|
64
|
+
if (service.user) {
|
|
65
|
+
yaml += ` user: ${service.user}\n`
|
|
66
|
+
}
|
|
67
|
+
|
|
63
68
|
yaml += ` restart: ${service.restart}\n\n`
|
|
64
69
|
|
|
65
70
|
return yaml
|
package/src/config/schema.ts
CHANGED
|
@@ -210,6 +210,8 @@ export interface AppDefinition {
|
|
|
210
210
|
homepage?: HomepageMeta
|
|
211
211
|
/** Auto-setup capability metadata */
|
|
212
212
|
autoSetup?: AutoSetupCapability
|
|
213
|
+
/** Use Docker's user: directive instead of PUID/PGID env vars (e.g., slskd) */
|
|
214
|
+
useDockerUser?: boolean
|
|
213
215
|
}
|
|
214
216
|
|
|
215
217
|
/** Auto-setup capability for an app */
|
|
@@ -508,7 +508,7 @@ export class FullAutoSetup extends BoxRenderable {
|
|
|
508
508
|
const port = app.port || def?.defaultPort || 7878
|
|
509
509
|
|
|
510
510
|
try {
|
|
511
|
-
await prowlarr.addArrApp(appType, app.id, port, appApiKey, "prowlarr", prowlarrPort)
|
|
511
|
+
await prowlarr.addArrApp(appType, app.id, port, appApiKey, "prowlarr", prowlarrPort, def?.prowlarrCategoryIds)
|
|
512
512
|
} catch {
|
|
513
513
|
// Skip - may already exist
|
|
514
514
|
}
|