@muhammedaksam/easiarr 1.4.1 → 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.
- package/dist/index.js +1255 -1342
- package/package.json +7 -7
package/dist/index.js
CHANGED
|
@@ -52,7 +52,7 @@ var package_default;
|
|
|
52
52
|
var init_package = __esm(() => {
|
|
53
53
|
package_default = {
|
|
54
54
|
name: "@muhammedaksam/easiarr",
|
|
55
|
-
version: "1.
|
|
55
|
+
version: "1.6.0",
|
|
56
56
|
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",
|
|
57
57
|
module: "dist/index.js",
|
|
58
58
|
type: "module",
|
|
@@ -108,20 +108,20 @@ var init_package = __esm(() => {
|
|
|
108
108
|
"@types/bcrypt": "^6.0.0",
|
|
109
109
|
"@types/bun": "latest",
|
|
110
110
|
"@types/jest": "^30.0.0",
|
|
111
|
-
"@types/node": "^26.
|
|
112
|
-
eslint: "^10.
|
|
111
|
+
"@types/node": "^26.1.1",
|
|
112
|
+
eslint: "^10.8.0",
|
|
113
113
|
"eslint-plugin-import": "^2.32.0",
|
|
114
114
|
jest: "^30.4.2",
|
|
115
115
|
jiti: "^2.7.0",
|
|
116
|
-
prettier: "^3.9.
|
|
117
|
-
"ts-jest": "^29.4.
|
|
118
|
-
"typescript-eslint": "^8.
|
|
116
|
+
prettier: "^3.9.6",
|
|
117
|
+
"ts-jest": "^29.4.12",
|
|
118
|
+
"typescript-eslint": "^8.65.0"
|
|
119
119
|
},
|
|
120
120
|
peerDependencies: {
|
|
121
121
|
typescript: "^5.9.3"
|
|
122
122
|
},
|
|
123
123
|
dependencies: {
|
|
124
|
-
"@opentui/core": "^0.4.
|
|
124
|
+
"@opentui/core": "^0.4.5",
|
|
125
125
|
bcrypt: "^6.0.0",
|
|
126
126
|
"socket.io-client": "^4.8.3",
|
|
127
127
|
yaml: "^2.9.0"
|
|
@@ -352,1258 +352,7 @@ var init_manager = __esm(() => {
|
|
|
352
352
|
init_schema();
|
|
353
353
|
});
|
|
354
354
|
|
|
355
|
-
// src/utils/arch.ts
|
|
356
|
-
function getSystemArch() {
|
|
357
|
-
const arch = process.arch;
|
|
358
|
-
switch (arch) {
|
|
359
|
-
case "x64":
|
|
360
|
-
case "ia32":
|
|
361
|
-
return "x64";
|
|
362
|
-
case "arm64":
|
|
363
|
-
return "arm64";
|
|
364
|
-
case "arm":
|
|
365
|
-
return "arm32";
|
|
366
|
-
default:
|
|
367
|
-
return "x64";
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
function isAppCompatible(app, arch) {
|
|
371
|
-
const systemArch = arch ?? getSystemArch();
|
|
372
|
-
if (!app.arch) {
|
|
373
|
-
return true;
|
|
374
|
-
}
|
|
375
|
-
if (app.arch.deprecated?.includes(systemArch)) {
|
|
376
|
-
return false;
|
|
377
|
-
}
|
|
378
|
-
if (app.arch.supported && !app.arch.supported.includes(systemArch)) {
|
|
379
|
-
return false;
|
|
380
|
-
}
|
|
381
|
-
return true;
|
|
382
|
-
}
|
|
383
|
-
function getArchWarning(app, arch) {
|
|
384
|
-
const systemArch = arch ?? getSystemArch();
|
|
385
|
-
if (!app.arch) {
|
|
386
|
-
return null;
|
|
387
|
-
}
|
|
388
|
-
if (app.arch.deprecated?.includes(systemArch)) {
|
|
389
|
-
return app.arch.warning || `${app.name} has deprecated support for ${systemArch}`;
|
|
390
|
-
}
|
|
391
|
-
if (app.arch.supported && !app.arch.supported.includes(systemArch)) {
|
|
392
|
-
return `${app.name} does not support ${systemArch} architecture`;
|
|
393
|
-
}
|
|
394
|
-
return null;
|
|
395
|
-
}
|
|
396
|
-
function isAppDeprecated(app, arch) {
|
|
397
|
-
const systemArch = arch ?? getSystemArch();
|
|
398
|
-
return app.arch?.deprecated?.includes(systemArch) ?? false;
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
// src/apps/registry.ts
|
|
402
|
-
var exports_registry = {};
|
|
403
|
-
__export(exports_registry, {
|
|
404
|
-
isAppDeprecated: () => isAppDeprecated,
|
|
405
|
-
isAppCompatible: () => isAppCompatible,
|
|
406
|
-
getSystemArch: () => getSystemArch,
|
|
407
|
-
getCompatibleApps: () => getCompatibleApps,
|
|
408
|
-
getArchWarning: () => getArchWarning,
|
|
409
|
-
getAppsWithArchWarnings: () => getAppsWithArchWarnings,
|
|
410
|
-
getAppsByCategory: () => getAppsByCategory,
|
|
411
|
-
getAppIds: () => getAppIds,
|
|
412
|
-
getApp: () => getApp,
|
|
413
|
-
getAllApps: () => getAllApps,
|
|
414
|
-
APPS: () => APPS
|
|
415
|
-
});
|
|
416
|
-
function getAppsByCategory() {
|
|
417
|
-
const result = {};
|
|
418
|
-
for (const app of Object.values(APPS)) {
|
|
419
|
-
if (!result[app.category]) {
|
|
420
|
-
result[app.category] = [];
|
|
421
|
-
}
|
|
422
|
-
result[app.category].push(app);
|
|
423
|
-
}
|
|
424
|
-
return result;
|
|
425
|
-
}
|
|
426
|
-
function getApp(id) {
|
|
427
|
-
return APPS[id];
|
|
428
|
-
}
|
|
429
|
-
function getAllApps() {
|
|
430
|
-
return Object.values(APPS);
|
|
431
|
-
}
|
|
432
|
-
function getAppIds() {
|
|
433
|
-
return Object.keys(APPS);
|
|
434
|
-
}
|
|
435
|
-
function getCompatibleApps() {
|
|
436
|
-
const arch = getSystemArch();
|
|
437
|
-
return Object.values(APPS).filter((app) => isAppCompatible(app, arch));
|
|
438
|
-
}
|
|
439
|
-
function getAppsWithArchWarnings() {
|
|
440
|
-
const arch = getSystemArch();
|
|
441
|
-
const result = [];
|
|
442
|
-
for (const app of Object.values(APPS)) {
|
|
443
|
-
const warning = getArchWarning(app, arch);
|
|
444
|
-
if (warning) {
|
|
445
|
-
result.push({ app, warning });
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
|
-
return result;
|
|
449
|
-
}
|
|
450
|
-
var APPS;
|
|
451
|
-
var init_registry = __esm(() => {
|
|
452
|
-
APPS = {
|
|
453
|
-
radarr: {
|
|
454
|
-
id: "radarr",
|
|
455
|
-
name: "Radarr",
|
|
456
|
-
description: "Movie collection manager",
|
|
457
|
-
category: "servarr",
|
|
458
|
-
defaultPort: 7878,
|
|
459
|
-
image: "lscr.io/linuxserver/radarr:latest",
|
|
460
|
-
puid: 13002,
|
|
461
|
-
pgid: 13000,
|
|
462
|
-
volumes: (root) => [`${root}/config/radarr:/config`, `${root}/data:/data`],
|
|
463
|
-
trashGuide: "docs/Radarr/",
|
|
464
|
-
apiKeyMeta: {
|
|
465
|
-
configFile: "config.xml",
|
|
466
|
-
parser: "regex",
|
|
467
|
-
selector: "<ApiKey>(.*?)</ApiKey>"
|
|
468
|
-
},
|
|
469
|
-
rootFolder: {
|
|
470
|
-
path: "/data/media/movies",
|
|
471
|
-
apiVersion: "v3"
|
|
472
|
-
},
|
|
473
|
-
prowlarrCategoryIds: [2000, 2010, 2020, 2030, 2040, 2045, 2050, 2060, 2070, 2080, 2090],
|
|
474
|
-
homepage: { icon: "radarr.png", widget: "radarr" },
|
|
475
|
-
logVolume: "/config/logs"
|
|
476
|
-
},
|
|
477
|
-
sonarr: {
|
|
478
|
-
id: "sonarr",
|
|
479
|
-
name: "Sonarr",
|
|
480
|
-
description: "TV series collection manager",
|
|
481
|
-
category: "servarr",
|
|
482
|
-
defaultPort: 8989,
|
|
483
|
-
image: "lscr.io/linuxserver/sonarr:latest",
|
|
484
|
-
puid: 13001,
|
|
485
|
-
pgid: 13000,
|
|
486
|
-
volumes: (root) => [`${root}/config/sonarr:/config`, `${root}/data:/data`],
|
|
487
|
-
trashGuide: "docs/Sonarr/",
|
|
488
|
-
apiKeyMeta: {
|
|
489
|
-
configFile: "config.xml",
|
|
490
|
-
parser: "regex",
|
|
491
|
-
selector: "<ApiKey>(.*?)</ApiKey>"
|
|
492
|
-
},
|
|
493
|
-
rootFolder: {
|
|
494
|
-
path: "/data/media/tv",
|
|
495
|
-
apiVersion: "v3"
|
|
496
|
-
},
|
|
497
|
-
prowlarrCategoryIds: [5000, 5010, 5020, 5030, 5040, 5045, 5050, 5060, 5070, 5080, 5090],
|
|
498
|
-
homepage: { icon: "sonarr.png", widget: "sonarr" },
|
|
499
|
-
logVolume: "/config/logs"
|
|
500
|
-
},
|
|
501
|
-
lidarr: {
|
|
502
|
-
id: "lidarr",
|
|
503
|
-
name: "Lidarr",
|
|
504
|
-
description: "Music collection manager",
|
|
505
|
-
category: "servarr",
|
|
506
|
-
defaultPort: 8686,
|
|
507
|
-
image: "lscr.io/linuxserver/lidarr:latest",
|
|
508
|
-
puid: 13003,
|
|
509
|
-
pgid: 13000,
|
|
510
|
-
volumes: (root) => [`${root}/config/lidarr:/config`, `${root}/data:/data`],
|
|
511
|
-
apiKeyMeta: {
|
|
512
|
-
configFile: "config.xml",
|
|
513
|
-
parser: "regex",
|
|
514
|
-
selector: "<ApiKey>(.*?)</ApiKey>"
|
|
515
|
-
},
|
|
516
|
-
rootFolder: {
|
|
517
|
-
path: "/data/media/music",
|
|
518
|
-
apiVersion: "v1"
|
|
519
|
-
},
|
|
520
|
-
prowlarrCategoryIds: [3000, 3010, 3020, 3030, 3040, 3050, 3060],
|
|
521
|
-
homepage: { icon: "lidarr.png", widget: "lidarr" },
|
|
522
|
-
logVolume: "/config/logs"
|
|
523
|
-
},
|
|
524
|
-
readarr: {
|
|
525
|
-
id: "readarr",
|
|
526
|
-
name: "Readarr",
|
|
527
|
-
description: "Book collection manager",
|
|
528
|
-
category: "servarr",
|
|
529
|
-
defaultPort: 8787,
|
|
530
|
-
image: "lscr.io/linuxserver/readarr:develop",
|
|
531
|
-
puid: 13004,
|
|
532
|
-
pgid: 13000,
|
|
533
|
-
volumes: (root) => [`${root}/config/readarr:/config`, `${root}/data:/data`],
|
|
534
|
-
apiKeyMeta: {
|
|
535
|
-
configFile: "config.xml",
|
|
536
|
-
parser: "regex",
|
|
537
|
-
selector: "<ApiKey>(.*?)</ApiKey>"
|
|
538
|
-
},
|
|
539
|
-
rootFolder: {
|
|
540
|
-
path: "/data/media/books",
|
|
541
|
-
apiVersion: "v1"
|
|
542
|
-
},
|
|
543
|
-
prowlarrCategoryIds: [7000, 7010, 7020, 7030, 7040, 7050, 7060],
|
|
544
|
-
arch: {
|
|
545
|
-
deprecated: ["arm64", "arm32"],
|
|
546
|
-
warning: "Readarr is deprecated - no ARM64 support (project abandoned by upstream)"
|
|
547
|
-
},
|
|
548
|
-
homepage: { icon: "readarr.png", widget: "readarr" },
|
|
549
|
-
logVolume: "/config/logs"
|
|
550
|
-
},
|
|
551
|
-
bazarr: {
|
|
552
|
-
id: "bazarr",
|
|
553
|
-
name: "Bazarr",
|
|
554
|
-
description: "Subtitle manager for Sonarr/Radarr",
|
|
555
|
-
category: "servarr",
|
|
556
|
-
defaultPort: 6767,
|
|
557
|
-
image: "lscr.io/linuxserver/bazarr:latest",
|
|
558
|
-
puid: 13013,
|
|
559
|
-
pgid: 13000,
|
|
560
|
-
volumes: (root) => [`${root}/config/bazarr:/config`, `${root}/data/media:/data/media`],
|
|
561
|
-
dependsOn: ["sonarr", "radarr"],
|
|
562
|
-
trashGuide: "docs/Bazarr/",
|
|
563
|
-
apiKeyMeta: {
|
|
564
|
-
configFile: "config/config.yaml",
|
|
565
|
-
parser: "yaml",
|
|
566
|
-
selector: "auth.apikey"
|
|
567
|
-
},
|
|
568
|
-
homepage: { icon: "bazarr.png", widget: "bazarr" },
|
|
569
|
-
logVolume: "/config/log"
|
|
570
|
-
},
|
|
571
|
-
mylar3: {
|
|
572
|
-
id: "mylar3",
|
|
573
|
-
name: "Mylar3",
|
|
574
|
-
description: "Comic book collection manager",
|
|
575
|
-
category: "servarr",
|
|
576
|
-
defaultPort: 8090,
|
|
577
|
-
image: "lscr.io/linuxserver/mylar3:latest",
|
|
578
|
-
puid: 13005,
|
|
579
|
-
pgid: 13000,
|
|
580
|
-
volumes: (root) => [`${root}/config/mylar3:/config`, `${root}/data:/data`],
|
|
581
|
-
apiKeyMeta: {
|
|
582
|
-
configFile: "mylar/config.ini",
|
|
583
|
-
parser: "ini",
|
|
584
|
-
section: "API",
|
|
585
|
-
selector: "api_key",
|
|
586
|
-
enabledKey: "api_enabled",
|
|
587
|
-
generateIfMissing: true
|
|
588
|
-
},
|
|
589
|
-
prowlarrCategoryIds: [7030],
|
|
590
|
-
homepage: { icon: "mylar.png", widget: "mylar" },
|
|
591
|
-
logVolume: "/app/mylar/logs"
|
|
592
|
-
},
|
|
593
|
-
whisparr: {
|
|
594
|
-
id: "whisparr",
|
|
595
|
-
name: "Whisparr",
|
|
596
|
-
description: "Adult media collection manager",
|
|
597
|
-
category: "servarr",
|
|
598
|
-
defaultPort: 6969,
|
|
599
|
-
image: "ghcr.io/hotio/whisparr:nightly",
|
|
600
|
-
puid: 13015,
|
|
601
|
-
pgid: 13000,
|
|
602
|
-
volumes: (root) => [`${root}/config/whisparr:/config`, `${root}/data:/data`],
|
|
603
|
-
apiKeyMeta: {
|
|
604
|
-
configFile: "config.xml",
|
|
605
|
-
parser: "regex",
|
|
606
|
-
selector: "<ApiKey>(.*?)</ApiKey>"
|
|
607
|
-
},
|
|
608
|
-
rootFolder: {
|
|
609
|
-
path: "/data/media/adult",
|
|
610
|
-
apiVersion: "v3"
|
|
611
|
-
},
|
|
612
|
-
prowlarrCategoryIds: [6000, 6010, 6020, 6030, 6040, 6045, 6050, 6060, 6070, 6080, 6090],
|
|
613
|
-
homepage: { icon: "whisparr.png", widget: "sonarr" },
|
|
614
|
-
logVolume: "/config/logs"
|
|
615
|
-
},
|
|
616
|
-
audiobookshelf: {
|
|
617
|
-
id: "audiobookshelf",
|
|
618
|
-
name: "Audiobookshelf",
|
|
619
|
-
description: "Audiobook and podcast server",
|
|
620
|
-
category: "servarr",
|
|
621
|
-
defaultPort: 13378,
|
|
622
|
-
image: "ghcr.io/advplyr/audiobookshelf:latest",
|
|
623
|
-
puid: 13014,
|
|
624
|
-
pgid: 13000,
|
|
625
|
-
volumes: (root) => [
|
|
626
|
-
`${root}/config/audiobookshelf:/config`,
|
|
627
|
-
`${root}/data/media/audiobooks:/audiobooks`,
|
|
628
|
-
`${root}/data/media/podcasts:/podcasts`,
|
|
629
|
-
`${root}/data/media/audiobookshelf-metadata:/metadata`
|
|
630
|
-
],
|
|
631
|
-
homepage: { icon: "audiobookshelf.png", widget: "audiobookshelf" },
|
|
632
|
-
logVolume: "/config/metadata/logs"
|
|
633
|
-
},
|
|
634
|
-
prowlarr: {
|
|
635
|
-
id: "prowlarr",
|
|
636
|
-
name: "Prowlarr",
|
|
637
|
-
description: "Indexer manager for *arr apps",
|
|
638
|
-
category: "indexer",
|
|
639
|
-
defaultPort: 9696,
|
|
640
|
-
image: "lscr.io/linuxserver/prowlarr:develop",
|
|
641
|
-
puid: 13006,
|
|
642
|
-
pgid: 13000,
|
|
643
|
-
volumes: (root) => [`${root}/config/prowlarr:/config`],
|
|
644
|
-
trashGuide: "docs/Prowlarr/",
|
|
645
|
-
apiKeyMeta: {
|
|
646
|
-
configFile: "config.xml",
|
|
647
|
-
parser: "regex",
|
|
648
|
-
selector: "<ApiKey>(.*?)</ApiKey>"
|
|
649
|
-
},
|
|
650
|
-
homepage: { icon: "prowlarr.png", widget: "prowlarr" },
|
|
651
|
-
logVolume: "/config/logs"
|
|
652
|
-
},
|
|
653
|
-
jackett: {
|
|
654
|
-
id: "jackett",
|
|
655
|
-
name: "Jackett",
|
|
656
|
-
description: "Alternative indexer manager",
|
|
657
|
-
category: "indexer",
|
|
658
|
-
defaultPort: 9117,
|
|
659
|
-
image: "lscr.io/linuxserver/jackett:latest",
|
|
660
|
-
puid: 13008,
|
|
661
|
-
pgid: 13000,
|
|
662
|
-
volumes: (root) => [`${root}/config/jackett:/config`],
|
|
663
|
-
apiKeyMeta: {
|
|
664
|
-
configFile: "Jackett/ServerConfig.json",
|
|
665
|
-
parser: "json",
|
|
666
|
-
selector: "APIKey"
|
|
667
|
-
},
|
|
668
|
-
homepage: { icon: "jackett.png", widget: "jackett" },
|
|
669
|
-
logVolume: "/config/logs"
|
|
670
|
-
},
|
|
671
|
-
flaresolverr: {
|
|
672
|
-
id: "flaresolverr",
|
|
673
|
-
name: "FlareSolverr",
|
|
674
|
-
description: "Cloudflare bypass proxy",
|
|
675
|
-
category: "indexer",
|
|
676
|
-
defaultPort: 8191,
|
|
677
|
-
image: "ghcr.io/flaresolverr/flaresolverr:latest",
|
|
678
|
-
puid: 0,
|
|
679
|
-
pgid: 0,
|
|
680
|
-
volumes: () => [],
|
|
681
|
-
environment: {
|
|
682
|
-
LOG_LEVEL: "info",
|
|
683
|
-
LOG_HTML: "false",
|
|
684
|
-
CAPTCHA_SOLVER: "none"
|
|
685
|
-
},
|
|
686
|
-
homepage: {
|
|
687
|
-
icon: "flaresolverr.png",
|
|
688
|
-
widget: "customapi",
|
|
689
|
-
widgetFields: {
|
|
690
|
-
url: "http://flaresolverr:8191",
|
|
691
|
-
mappings: JSON.stringify([
|
|
692
|
-
{ field: "msg", label: "Status" },
|
|
693
|
-
{ field: "version", label: "Version" }
|
|
694
|
-
])
|
|
695
|
-
}
|
|
696
|
-
}
|
|
697
|
-
},
|
|
698
|
-
qbittorrent: {
|
|
699
|
-
id: "qbittorrent",
|
|
700
|
-
name: "qBittorrent",
|
|
701
|
-
description: "BitTorrent client",
|
|
702
|
-
category: "downloader",
|
|
703
|
-
defaultPort: 8080,
|
|
704
|
-
image: "lscr.io/linuxserver/qbittorrent:latest",
|
|
705
|
-
puid: 13007,
|
|
706
|
-
pgid: 13000,
|
|
707
|
-
volumes: (root) => [`${root}/config/qbittorrent:/config`, `${root}/data:/data`],
|
|
708
|
-
environment: { WEBUI_PORT: "8080" },
|
|
709
|
-
secrets: [
|
|
710
|
-
{
|
|
711
|
-
name: "USERNAME_QBITTORRENT",
|
|
712
|
-
description: "Username for qBittorrent WebUI",
|
|
713
|
-
required: false,
|
|
714
|
-
default: "admin"
|
|
715
|
-
},
|
|
716
|
-
{
|
|
717
|
-
name: "PASSWORD_QBITTORRENT",
|
|
718
|
-
description: "Password for qBittorrent WebUI",
|
|
719
|
-
required: false,
|
|
720
|
-
mask: true
|
|
721
|
-
}
|
|
722
|
-
],
|
|
723
|
-
trashGuide: "docs/Downloaders/qBittorrent/",
|
|
724
|
-
homepage: { icon: "qbittorrent.png", widget: "qbittorrent" },
|
|
725
|
-
logVolume: "/config/qBittorrent/logs"
|
|
726
|
-
},
|
|
727
|
-
sabnzbd: {
|
|
728
|
-
id: "sabnzbd",
|
|
729
|
-
name: "SABnzbd",
|
|
730
|
-
description: "Usenet downloader",
|
|
731
|
-
category: "downloader",
|
|
732
|
-
defaultPort: 8081,
|
|
733
|
-
image: "lscr.io/linuxserver/sabnzbd:latest",
|
|
734
|
-
puid: 13011,
|
|
735
|
-
pgid: 13000,
|
|
736
|
-
volumes: (root) => [`${root}/config/sabnzbd:/config`, `${root}/data:/data`],
|
|
737
|
-
trashGuide: "docs/Downloaders/SABnzbd/",
|
|
738
|
-
apiKeyMeta: {
|
|
739
|
-
configFile: "sabnzbd.ini",
|
|
740
|
-
parser: "regex",
|
|
741
|
-
selector: "api_key\\s*=\\s*(.+)"
|
|
742
|
-
},
|
|
743
|
-
homepage: { icon: "sabnzbd.png", widget: "sabnzbd" },
|
|
744
|
-
logVolume: "/config/logs"
|
|
745
|
-
},
|
|
746
|
-
slskd: {
|
|
747
|
-
id: "slskd",
|
|
748
|
-
name: "Slskd",
|
|
749
|
-
description: "Soulseek client for music downloads",
|
|
750
|
-
category: "downloader",
|
|
751
|
-
defaultPort: 5030,
|
|
752
|
-
image: "slskd/slskd",
|
|
753
|
-
puid: 0,
|
|
754
|
-
pgid: 0,
|
|
755
|
-
useDockerUser: true,
|
|
756
|
-
volumes: (root) => [`${root}/config/slskd:/app`, `${root}/data:/data`],
|
|
757
|
-
secondaryPorts: ["5031:5031", "50300:50300"],
|
|
758
|
-
environment: {
|
|
759
|
-
SLSKD_REMOTE_CONFIGURATION: "true",
|
|
760
|
-
SLSKD_USERNAME: "${USERNAME_GLOBAL}",
|
|
761
|
-
SLSKD_PASSWORD: "${PASSWORD_GLOBAL}",
|
|
762
|
-
SLSKD_SLSK_USERNAME: "${USERNAME_SOULSEEK}",
|
|
763
|
-
SLSKD_SLSK_PASSWORD: "${PASSWORD_SOULSEEK}"
|
|
764
|
-
},
|
|
765
|
-
secrets: [
|
|
766
|
-
{
|
|
767
|
-
name: "USERNAME_SOULSEEK",
|
|
768
|
-
description: "Soulseek network username (your Soulseek account)",
|
|
769
|
-
required: true
|
|
770
|
-
},
|
|
771
|
-
{
|
|
772
|
-
name: "PASSWORD_SOULSEEK",
|
|
773
|
-
description: "Soulseek network password",
|
|
774
|
-
required: true,
|
|
775
|
-
mask: true
|
|
776
|
-
}
|
|
777
|
-
],
|
|
778
|
-
homepage: { icon: "slskd.png", widget: "slskd" },
|
|
779
|
-
autoSetup: {
|
|
780
|
-
type: "partial",
|
|
781
|
-
description: "Generates slskd.yml with API key for Homepage widget and Soularr integration"
|
|
782
|
-
},
|
|
783
|
-
logVolume: "/app/logs"
|
|
784
|
-
},
|
|
785
|
-
soularr: {
|
|
786
|
-
id: "soularr",
|
|
787
|
-
name: "Soularr",
|
|
788
|
-
description: "Connects Lidarr with Soulseek via Slskd",
|
|
789
|
-
category: "downloader",
|
|
790
|
-
defaultPort: 0,
|
|
791
|
-
image: "mrusse08/soularr:latest",
|
|
792
|
-
puid: 13017,
|
|
793
|
-
pgid: 13000,
|
|
794
|
-
volumes: (root) => [`${root}/data/slskd_downloads:/downloads`, `${root}/config/soularr:/data`],
|
|
795
|
-
environment: {
|
|
796
|
-
SCRIPT_INTERVAL: "300"
|
|
797
|
-
},
|
|
798
|
-
dependsOn: ["lidarr", "slskd"]
|
|
799
|
-
},
|
|
800
|
-
plex: {
|
|
801
|
-
id: "plex",
|
|
802
|
-
name: "Plex",
|
|
803
|
-
description: "Media server with streaming",
|
|
804
|
-
category: "mediaserver",
|
|
805
|
-
defaultPort: 32400,
|
|
806
|
-
image: "lscr.io/linuxserver/plex:latest",
|
|
807
|
-
puid: 13010,
|
|
808
|
-
pgid: 13000,
|
|
809
|
-
volumes: (root) => [`${root}/config/plex:/config`, `${root}/data/media:/data/media`],
|
|
810
|
-
environment: { VERSION: "docker", PLEX_CLAIM: "${PLEX_CLAIM}" },
|
|
811
|
-
trashGuide: "docs/Plex/",
|
|
812
|
-
apiKeyMeta: {
|
|
813
|
-
configFile: "Library/Application Support/Plex Media Server/Preferences.xml",
|
|
814
|
-
parser: "regex",
|
|
815
|
-
selector: 'PlexOnlineToken="([^"]+)"'
|
|
816
|
-
},
|
|
817
|
-
homepage: { icon: "plex.png", widget: "plex" },
|
|
818
|
-
logVolume: "/config/Library/Application Support/Plex Media Server/Logs",
|
|
819
|
-
autoSetup: {
|
|
820
|
-
type: "full",
|
|
821
|
-
description: "Claim server with token, create media libraries",
|
|
822
|
-
envVars: ["PLEX_CLAIM"]
|
|
823
|
-
}
|
|
824
|
-
},
|
|
825
|
-
jellyfin: {
|
|
826
|
-
id: "jellyfin",
|
|
827
|
-
name: "Jellyfin",
|
|
828
|
-
description: "Free open-source media server",
|
|
829
|
-
category: "mediaserver",
|
|
830
|
-
defaultPort: 8096,
|
|
831
|
-
image: "lscr.io/linuxserver/jellyfin:latest",
|
|
832
|
-
puid: 0,
|
|
833
|
-
pgid: 13000,
|
|
834
|
-
volumes: (root) => [`${root}/config/jellyfin:/config`, `${root}/data/media:/data/media`],
|
|
835
|
-
homepage: { icon: "jellyfin.png", widget: "jellyfin" },
|
|
836
|
-
logVolume: "/config/log"
|
|
837
|
-
},
|
|
838
|
-
tautulli: {
|
|
839
|
-
id: "tautulli",
|
|
840
|
-
name: "Tautulli",
|
|
841
|
-
description: "Plex monitoring and statistics",
|
|
842
|
-
category: "mediaserver",
|
|
843
|
-
defaultPort: 8181,
|
|
844
|
-
image: "lscr.io/linuxserver/tautulli:latest",
|
|
845
|
-
puid: 0,
|
|
846
|
-
pgid: 13000,
|
|
847
|
-
volumes: (root) => [`${root}/config/tautulli:/config`],
|
|
848
|
-
dependsOn: ["plex"],
|
|
849
|
-
apiKeyMeta: {
|
|
850
|
-
configFile: "config.ini",
|
|
851
|
-
parser: "regex",
|
|
852
|
-
selector: "api_key\\s*=\\s*(.+)"
|
|
853
|
-
},
|
|
854
|
-
homepage: { icon: "tautulli.png", widget: "tautulli" },
|
|
855
|
-
autoSetup: {
|
|
856
|
-
type: "partial",
|
|
857
|
-
description: "Connect to Plex, enable API",
|
|
858
|
-
requires: ["plex"]
|
|
859
|
-
},
|
|
860
|
-
logVolume: "/config/logs"
|
|
861
|
-
},
|
|
862
|
-
tdarr: {
|
|
863
|
-
id: "tdarr",
|
|
864
|
-
name: "Tdarr",
|
|
865
|
-
description: "Audio/video transcoding automation",
|
|
866
|
-
category: "mediaserver",
|
|
867
|
-
defaultPort: 8265,
|
|
868
|
-
image: "ghcr.io/haveagitgat/tdarr:latest",
|
|
869
|
-
puid: 0,
|
|
870
|
-
pgid: 13000,
|
|
871
|
-
volumes: (root) => [
|
|
872
|
-
`${root}/config/tdarr/server:/app/server`,
|
|
873
|
-
`${root}/config/tdarr/configs:/app/configs`,
|
|
874
|
-
`${root}/config/tdarr/logs:/app/logs`,
|
|
875
|
-
`${root}/data/media:/data`
|
|
876
|
-
],
|
|
877
|
-
environment: { serverIP: "0.0.0.0", internalNode: "true" },
|
|
878
|
-
homepage: { icon: "tdarr.png", widget: "tdarr" },
|
|
879
|
-
logVolume: "/app/logs"
|
|
880
|
-
},
|
|
881
|
-
overseerr: {
|
|
882
|
-
id: "overseerr",
|
|
883
|
-
name: "Overseerr",
|
|
884
|
-
description: "Request management for Plex",
|
|
885
|
-
category: "request",
|
|
886
|
-
defaultPort: 5055,
|
|
887
|
-
image: "sctx/overseerr:latest",
|
|
888
|
-
puid: 13009,
|
|
889
|
-
pgid: 13000,
|
|
890
|
-
volumes: (root) => [`${root}/config/overseerr:/app/config`],
|
|
891
|
-
dependsOn: ["plex"],
|
|
892
|
-
apiKeyMeta: {
|
|
893
|
-
configFile: "settings.json",
|
|
894
|
-
parser: "json",
|
|
895
|
-
selector: "main.apiKey"
|
|
896
|
-
},
|
|
897
|
-
homepage: { icon: "overseerr.png", widget: "overseerr" },
|
|
898
|
-
autoSetup: {
|
|
899
|
-
type: "full",
|
|
900
|
-
description: "Connect to Plex, configure Radarr/Sonarr",
|
|
901
|
-
requires: ["plex"]
|
|
902
|
-
},
|
|
903
|
-
logVolume: "/app/config/logs"
|
|
904
|
-
},
|
|
905
|
-
jellyseerr: {
|
|
906
|
-
id: "jellyseerr",
|
|
907
|
-
name: "Jellyseerr",
|
|
908
|
-
description: "Request management for Jellyfin",
|
|
909
|
-
category: "request",
|
|
910
|
-
defaultPort: 5055,
|
|
911
|
-
image: "fallenbagel/jellyseerr:latest",
|
|
912
|
-
puid: 13012,
|
|
913
|
-
pgid: 13000,
|
|
914
|
-
volumes: (root) => [`${root}/config/jellyseerr:/app/config`],
|
|
915
|
-
dependsOn: ["jellyfin"],
|
|
916
|
-
apiKeyMeta: {
|
|
917
|
-
configFile: "settings.json",
|
|
918
|
-
parser: "json",
|
|
919
|
-
selector: "main.apiKey"
|
|
920
|
-
},
|
|
921
|
-
homepage: { icon: "jellyseerr.png", widget: "jellyseerr" },
|
|
922
|
-
logVolume: "/app/config/logs"
|
|
923
|
-
},
|
|
924
|
-
homarr: {
|
|
925
|
-
id: "homarr",
|
|
926
|
-
name: "Homarr",
|
|
927
|
-
description: "Modern dashboard for all services",
|
|
928
|
-
category: "dashboard",
|
|
929
|
-
defaultPort: 7575,
|
|
930
|
-
image: "ghcr.io/ajnart/homarr:latest",
|
|
931
|
-
puid: 0,
|
|
932
|
-
pgid: 0,
|
|
933
|
-
volumes: (root) => [
|
|
934
|
-
`${root}/config/homarr/configs:/app/data/configs`,
|
|
935
|
-
`${root}/config/homarr/icons:/app/public/icons`,
|
|
936
|
-
`${root}/config/homarr/data:/data`,
|
|
937
|
-
"/var/run/docker.sock:/var/run/docker.sock"
|
|
938
|
-
],
|
|
939
|
-
homepage: { icon: "homarr.png" },
|
|
940
|
-
logVolume: "/app/data/logs"
|
|
941
|
-
},
|
|
942
|
-
heimdall: {
|
|
943
|
-
id: "heimdall",
|
|
944
|
-
name: "Heimdall",
|
|
945
|
-
description: "Application dashboard and launcher",
|
|
946
|
-
category: "dashboard",
|
|
947
|
-
defaultPort: 8082,
|
|
948
|
-
image: "lscr.io/linuxserver/heimdall:latest",
|
|
949
|
-
puid: 0,
|
|
950
|
-
pgid: 13000,
|
|
951
|
-
volumes: (root) => [`${root}/config/heimdall:/config`],
|
|
952
|
-
homepage: { icon: "heimdall.png" },
|
|
953
|
-
logVolume: "/config/log"
|
|
954
|
-
},
|
|
955
|
-
homepage: {
|
|
956
|
-
id: "homepage",
|
|
957
|
-
name: "Homepage",
|
|
958
|
-
description: "Highly customizable application dashboard",
|
|
959
|
-
category: "dashboard",
|
|
960
|
-
defaultPort: 3009,
|
|
961
|
-
internalPort: 3000,
|
|
962
|
-
image: "ghcr.io/gethomepage/homepage:latest",
|
|
963
|
-
puid: 0,
|
|
964
|
-
pgid: 0,
|
|
965
|
-
volumes: (root) => [
|
|
966
|
-
`${root}/config/homepage:/app/config`,
|
|
967
|
-
"/var/run/docker.sock:/var/run/docker.sock"
|
|
968
|
-
],
|
|
969
|
-
environment: {
|
|
970
|
-
HOMEPAGE_ALLOWED_HOSTS: "homepage,homepage.${CLOUDFLARE_DNS_ZONE},${CLOUDFLARE_DNS_ZONE},localhost,${LOCAL_DOCKER_IP},${LOCAL_DOCKER_IP}:3009"
|
|
971
|
-
},
|
|
972
|
-
logVolume: "/app/config/logs"
|
|
973
|
-
},
|
|
974
|
-
portainer: {
|
|
975
|
-
id: "portainer",
|
|
976
|
-
name: "Portainer",
|
|
977
|
-
description: "Docker container management UI",
|
|
978
|
-
category: "utility",
|
|
979
|
-
defaultPort: 9000,
|
|
980
|
-
image: "portainer/portainer-ce:latest",
|
|
981
|
-
puid: 0,
|
|
982
|
-
pgid: 0,
|
|
983
|
-
volumes: (root) => [
|
|
984
|
-
`${root}/config/portainer:/data`,
|
|
985
|
-
"/var/run/docker.sock:/var/run/docker.sock"
|
|
986
|
-
],
|
|
987
|
-
minPasswordLength: 12,
|
|
988
|
-
homepage: { icon: "portainer.png", widget: "portainer" },
|
|
989
|
-
logVolume: "/data/logs"
|
|
990
|
-
},
|
|
991
|
-
huntarr: {
|
|
992
|
-
id: "huntarr",
|
|
993
|
-
name: "Huntarr",
|
|
994
|
-
description: "Missing content manager for *arr apps",
|
|
995
|
-
category: "utility",
|
|
996
|
-
defaultPort: 9705,
|
|
997
|
-
image: "huntarr/huntarr:latest",
|
|
998
|
-
puid: 0,
|
|
999
|
-
pgid: 13000,
|
|
1000
|
-
volumes: (root) => [`${root}/config/huntarr:/config`],
|
|
1001
|
-
dependsOn: ["sonarr", "radarr", "lidarr", "readarr"],
|
|
1002
|
-
homepage: {
|
|
1003
|
-
icon: "huntarr.png",
|
|
1004
|
-
widget: "customapi",
|
|
1005
|
-
widgetFields: {
|
|
1006
|
-
url: "http://huntarr:9705/api/cycle/status",
|
|
1007
|
-
mappings: JSON.stringify([
|
|
1008
|
-
{ field: "sonarr.next_cycle", label: "Sonarr", format: "relativeDate" },
|
|
1009
|
-
{ field: "radarr.next_cycle", label: "Radarr", format: "relativeDate" },
|
|
1010
|
-
{ field: "lidarr.next_cycle", label: "Lidarr", format: "relativeDate" },
|
|
1011
|
-
{ field: "readarr.next_cycle", label: "Readarr", format: "relativeDate" },
|
|
1012
|
-
{ field: "whisparr.next_cycle", label: "Whisparr", format: "relativeDate" }
|
|
1013
|
-
])
|
|
1014
|
-
}
|
|
1015
|
-
},
|
|
1016
|
-
autoSetup: {
|
|
1017
|
-
type: "full",
|
|
1018
|
-
description: "Test connections to Sonarr, Radarr, Lidarr, Readarr, Whisparr",
|
|
1019
|
-
requires: ["sonarr", "radarr"]
|
|
1020
|
-
},
|
|
1021
|
-
logVolume: "/config/logs"
|
|
1022
|
-
},
|
|
1023
|
-
maintainerr: {
|
|
1024
|
-
id: "maintainerr",
|
|
1025
|
-
name: "Maintainerr",
|
|
1026
|
-
description: "Automated media management and cleanup for Plex",
|
|
1027
|
-
category: "utility",
|
|
1028
|
-
defaultPort: 6246,
|
|
1029
|
-
image: "ghcr.io/maintainerr/maintainerr:latest",
|
|
1030
|
-
puid: 0,
|
|
1031
|
-
pgid: 13000,
|
|
1032
|
-
volumes: (root) => [`${root}/config/maintainerr:/opt/data`],
|
|
1033
|
-
dependsOn: ["plex"],
|
|
1034
|
-
homepage: {
|
|
1035
|
-
icon: "maintainerr.png",
|
|
1036
|
-
widget: "customapi",
|
|
1037
|
-
widgetFields: {
|
|
1038
|
-
url: "http://maintainerr:6246/api/settings/version",
|
|
1039
|
-
mappings: JSON.stringify([{ field: "version", label: "Version" }])
|
|
1040
|
-
}
|
|
1041
|
-
},
|
|
1042
|
-
autoSetup: {
|
|
1043
|
-
type: "full",
|
|
1044
|
-
description: "Generate API key, configure Plex/Radarr/Sonarr/Overseerr/Tautulli connections",
|
|
1045
|
-
requires: ["plex"]
|
|
1046
|
-
},
|
|
1047
|
-
logVolume: "/opt/data/logs"
|
|
1048
|
-
},
|
|
1049
|
-
unpackerr: {
|
|
1050
|
-
id: "unpackerr",
|
|
1051
|
-
name: "Unpackerr",
|
|
1052
|
-
description: "Archive extraction for *arr apps",
|
|
1053
|
-
category: "utility",
|
|
1054
|
-
defaultPort: 5656,
|
|
1055
|
-
image: "golift/unpackerr",
|
|
1056
|
-
puid: 0,
|
|
1057
|
-
pgid: 13000,
|
|
1058
|
-
volumes: (root) => [`${root}/config/unpackerr:/config`, `${root}/data:/data`],
|
|
1059
|
-
logVolume: "/config/logs"
|
|
1060
|
-
},
|
|
1061
|
-
filebot: {
|
|
1062
|
-
id: "filebot",
|
|
1063
|
-
name: "FileBot",
|
|
1064
|
-
description: "Media file renaming and automator",
|
|
1065
|
-
category: "utility",
|
|
1066
|
-
defaultPort: 5452,
|
|
1067
|
-
image: "rednoah/filebot",
|
|
1068
|
-
puid: 13000,
|
|
1069
|
-
pgid: 13000,
|
|
1070
|
-
volumes: (root) => [`${root}/config/filebot:/data`, `${root}/data:/data`],
|
|
1071
|
-
environment: { DARK_MODE: "1" },
|
|
1072
|
-
logVolume: "/data/logs"
|
|
1073
|
-
},
|
|
1074
|
-
chromium: {
|
|
1075
|
-
id: "chromium",
|
|
1076
|
-
name: "Chromium",
|
|
1077
|
-
description: "Web browser for secure remote browsing",
|
|
1078
|
-
category: "utility",
|
|
1079
|
-
defaultPort: 3000,
|
|
1080
|
-
image: "lscr.io/linuxserver/chromium:latest",
|
|
1081
|
-
puid: 13000,
|
|
1082
|
-
pgid: 13000,
|
|
1083
|
-
volumes: (root) => [`${root}/config/chromium:/config`],
|
|
1084
|
-
environment: { TITLE: "Chromium" },
|
|
1085
|
-
logVolume: "/config/logs"
|
|
1086
|
-
},
|
|
1087
|
-
guacamole: {
|
|
1088
|
-
id: "guacamole",
|
|
1089
|
-
name: "Guacamole",
|
|
1090
|
-
description: "Clientless remote desktop gateway",
|
|
1091
|
-
category: "utility",
|
|
1092
|
-
defaultPort: 8080,
|
|
1093
|
-
image: "guacamole/guacamole",
|
|
1094
|
-
puid: 0,
|
|
1095
|
-
pgid: 0,
|
|
1096
|
-
volumes: (root) => [`${root}/config/guacamole:/config`],
|
|
1097
|
-
environment: {
|
|
1098
|
-
WEBAPP_CONTEXT: "ROOT",
|
|
1099
|
-
GUACD_HOSTNAME: "guacd",
|
|
1100
|
-
POSTGRESQL_HOSTNAME: "postgresql",
|
|
1101
|
-
POSTGRESQL_DATABASE: "guacamole",
|
|
1102
|
-
POSTGRESQL_USER: "${USERNAME_POSTGRESQL}",
|
|
1103
|
-
POSTGRESQL_PASSWORD: "${PASSWORD_POSTGRESQL}"
|
|
1104
|
-
},
|
|
1105
|
-
dependsOn: ["guacd", "postgresql"],
|
|
1106
|
-
secrets: [
|
|
1107
|
-
{
|
|
1108
|
-
name: "USERNAME_POSTGRESQL",
|
|
1109
|
-
description: "PostgreSQL Username",
|
|
1110
|
-
required: true,
|
|
1111
|
-
default: "postgres"
|
|
1112
|
-
},
|
|
1113
|
-
{
|
|
1114
|
-
name: "PASSWORD_POSTGRESQL",
|
|
1115
|
-
description: "PostgreSQL Password",
|
|
1116
|
-
required: true,
|
|
1117
|
-
mask: true
|
|
1118
|
-
}
|
|
1119
|
-
],
|
|
1120
|
-
logVolume: "/guacamole/logs"
|
|
1121
|
-
},
|
|
1122
|
-
guacd: {
|
|
1123
|
-
id: "guacd",
|
|
1124
|
-
name: "Guacd",
|
|
1125
|
-
description: "Guacamole proxy daemon",
|
|
1126
|
-
category: "utility",
|
|
1127
|
-
defaultPort: 4822,
|
|
1128
|
-
image: "guacamole/guacd",
|
|
1129
|
-
puid: 0,
|
|
1130
|
-
pgid: 13000,
|
|
1131
|
-
volumes: (root) => [`${root}/config/guacd:/config`],
|
|
1132
|
-
dependsOn: ["postgresql"],
|
|
1133
|
-
logVolume: "/guacd/logs"
|
|
1134
|
-
},
|
|
1135
|
-
"ddns-updater": {
|
|
1136
|
-
id: "ddns-updater",
|
|
1137
|
-
name: "DDNS-Updater",
|
|
1138
|
-
description: "Dynamic DNS record updater",
|
|
1139
|
-
category: "utility",
|
|
1140
|
-
defaultPort: 8000,
|
|
1141
|
-
image: "qmcgaw/ddns-updater",
|
|
1142
|
-
puid: 13000,
|
|
1143
|
-
pgid: 13000,
|
|
1144
|
-
volumes: (root) => [`${root}/config/ddns-updater:/data`],
|
|
1145
|
-
logVolume: "/data/logs"
|
|
1146
|
-
},
|
|
1147
|
-
easiarr: {
|
|
1148
|
-
id: "easiarr",
|
|
1149
|
-
name: "easiarr",
|
|
1150
|
-
description: "Exposes easiarr config and bookmarks for Homepage dashboard",
|
|
1151
|
-
category: "utility",
|
|
1152
|
-
defaultPort: 3010,
|
|
1153
|
-
internalPort: 8080,
|
|
1154
|
-
image: "halverneus/static-file-server:latest",
|
|
1155
|
-
puid: 0,
|
|
1156
|
-
pgid: 0,
|
|
1157
|
-
volumes: () => [
|
|
1158
|
-
"${XDG_CONFIG_HOME}/easiarr/config.json:/web/config.json:ro",
|
|
1159
|
-
"${XDG_CONFIG_HOME}/easiarr/bookmarks-local.html:/web/bookmarks-local.html:ro",
|
|
1160
|
-
"${XDG_CONFIG_HOME}/easiarr/bookmarks-remote.html:/web/bookmarks-remote.html:ro"
|
|
1161
|
-
],
|
|
1162
|
-
environment: {
|
|
1163
|
-
FOLDER: "/web",
|
|
1164
|
-
CORS: "true"
|
|
1165
|
-
},
|
|
1166
|
-
homepage: {
|
|
1167
|
-
icon: "mdi-docker",
|
|
1168
|
-
widget: "customapi",
|
|
1169
|
-
widgetFields: {
|
|
1170
|
-
url: "http://easiarr:8080/config.json",
|
|
1171
|
-
mappings: JSON.stringify([
|
|
1172
|
-
{ field: "version", label: "Version" },
|
|
1173
|
-
{ field: "apps.length", label: "Apps" }
|
|
1174
|
-
])
|
|
1175
|
-
}
|
|
1176
|
-
}
|
|
1177
|
-
},
|
|
1178
|
-
recyclarr: {
|
|
1179
|
-
id: "recyclarr",
|
|
1180
|
-
name: "Recyclarr",
|
|
1181
|
-
description: "Automatic TRaSH Guides profile sync for *arr apps",
|
|
1182
|
-
category: "utility",
|
|
1183
|
-
defaultPort: 0,
|
|
1184
|
-
image: "ghcr.io/recyclarr/recyclarr:latest",
|
|
1185
|
-
puid: 0,
|
|
1186
|
-
pgid: 0,
|
|
1187
|
-
useDockerUser: true,
|
|
1188
|
-
volumes: (root) => [`${root}/config/recyclarr:/config`],
|
|
1189
|
-
environment: {
|
|
1190
|
-
RECYCLARR_CREATE_CONFIG: "false",
|
|
1191
|
-
CRON_SCHEDULE: "@daily"
|
|
1192
|
-
},
|
|
1193
|
-
dependsOn: ["radarr", "sonarr"],
|
|
1194
|
-
autoSetup: {
|
|
1195
|
-
type: "full",
|
|
1196
|
-
description: "Generate recyclarr.yml config for enabled *arr apps with TRaSH profiles",
|
|
1197
|
-
requires: ["radarr", "sonarr"]
|
|
1198
|
-
}
|
|
1199
|
-
},
|
|
1200
|
-
profilarr: {
|
|
1201
|
-
id: "profilarr",
|
|
1202
|
-
name: "Profilarr",
|
|
1203
|
-
description: "Web UI for managing TRaSH Guides profiles (alternative to Recyclarr)",
|
|
1204
|
-
category: "utility",
|
|
1205
|
-
defaultPort: 6868,
|
|
1206
|
-
image: "santiagosayshey/profilarr:latest",
|
|
1207
|
-
puid: 1000,
|
|
1208
|
-
pgid: 1000,
|
|
1209
|
-
volumes: (root) => [`${root}/config/profilarr:/config`],
|
|
1210
|
-
dependsOn: ["radarr", "sonarr"],
|
|
1211
|
-
homepage: {
|
|
1212
|
-
icon: "profilarr"
|
|
1213
|
-
}
|
|
1214
|
-
},
|
|
1215
|
-
gluetun: {
|
|
1216
|
-
id: "gluetun",
|
|
1217
|
-
name: "Gluetun",
|
|
1218
|
-
description: "VPN client container for routing traffic",
|
|
1219
|
-
category: "vpn",
|
|
1220
|
-
defaultPort: 8888,
|
|
1221
|
-
image: "qmcgaw/gluetun:latest",
|
|
1222
|
-
puid: 0,
|
|
1223
|
-
pgid: 0,
|
|
1224
|
-
cap_add: ["NET_ADMIN"],
|
|
1225
|
-
devices: ["/dev/net/tun:/dev/net/tun"],
|
|
1226
|
-
volumes: (root) => [`${root}/config/gluetun:/gluetun`],
|
|
1227
|
-
environment: {
|
|
1228
|
-
VPN_SERVICE_PROVIDER: "${VPN_SERVICE_PROVIDER}",
|
|
1229
|
-
OPENVPN_USER: "${USERNAME_VPN}",
|
|
1230
|
-
OPENVPN_PASSWORD: "${PASSWORD_VPN}",
|
|
1231
|
-
WIREGUARD_PRIVATE_KEY: "${WIREGUARD_PRIVATE_KEY}",
|
|
1232
|
-
HTTPPROXY: "on",
|
|
1233
|
-
SHADOWSOCKS: "on"
|
|
1234
|
-
},
|
|
1235
|
-
secrets: [
|
|
1236
|
-
{
|
|
1237
|
-
name: "VPN_SERVICE_PROVIDER",
|
|
1238
|
-
description: "VPN Provider (e.g. custom, airvpn)",
|
|
1239
|
-
required: true,
|
|
1240
|
-
default: "custom"
|
|
1241
|
-
},
|
|
1242
|
-
{
|
|
1243
|
-
name: "USERNAME_VPN",
|
|
1244
|
-
description: "OpenVPN Username",
|
|
1245
|
-
required: false
|
|
1246
|
-
},
|
|
1247
|
-
{
|
|
1248
|
-
name: "PASSWORD_VPN",
|
|
1249
|
-
description: "OpenVPN Password",
|
|
1250
|
-
required: false,
|
|
1251
|
-
mask: true
|
|
1252
|
-
},
|
|
1253
|
-
{
|
|
1254
|
-
name: "WIREGUARD_PRIVATE_KEY",
|
|
1255
|
-
description: "WireGuard Private Key",
|
|
1256
|
-
required: false,
|
|
1257
|
-
mask: true
|
|
1258
|
-
}
|
|
1259
|
-
],
|
|
1260
|
-
homepage: { icon: "gluetun.png", widget: "gluetun" },
|
|
1261
|
-
logVolume: "/gluetun"
|
|
1262
|
-
},
|
|
1263
|
-
grafana: {
|
|
1264
|
-
id: "grafana",
|
|
1265
|
-
name: "Grafana",
|
|
1266
|
-
description: "Visual monitoring dashboard",
|
|
1267
|
-
category: "monitoring",
|
|
1268
|
-
defaultPort: 3001,
|
|
1269
|
-
image: "grafana/grafana-enterprise",
|
|
1270
|
-
puid: 0,
|
|
1271
|
-
pgid: 13000,
|
|
1272
|
-
volumes: (root) => [`${root}/config/grafana:/var/lib/grafana`],
|
|
1273
|
-
homepage: { icon: "grafana.png", widget: "grafana" },
|
|
1274
|
-
autoSetup: {
|
|
1275
|
-
type: "full",
|
|
1276
|
-
description: "Setup admin user, configure Prometheus datasource",
|
|
1277
|
-
requires: ["prometheus"]
|
|
1278
|
-
},
|
|
1279
|
-
logVolume: "/var/log/grafana"
|
|
1280
|
-
},
|
|
1281
|
-
prometheus: {
|
|
1282
|
-
id: "prometheus",
|
|
1283
|
-
name: "Prometheus",
|
|
1284
|
-
description: "Systems and service monitoring",
|
|
1285
|
-
category: "monitoring",
|
|
1286
|
-
defaultPort: 9090,
|
|
1287
|
-
image: "prom/prometheus",
|
|
1288
|
-
puid: 0,
|
|
1289
|
-
pgid: 13000,
|
|
1290
|
-
volumes: (root) => [`${root}/config/prometheus:/prometheus`],
|
|
1291
|
-
homepage: { icon: "prometheus.png", widget: "prometheus" },
|
|
1292
|
-
logVolume: "/prometheus/logs"
|
|
1293
|
-
},
|
|
1294
|
-
dozzle: {
|
|
1295
|
-
id: "dozzle",
|
|
1296
|
-
name: "Dozzle",
|
|
1297
|
-
description: "Real-time log viewer for Docker containers",
|
|
1298
|
-
category: "monitoring",
|
|
1299
|
-
defaultPort: 8080,
|
|
1300
|
-
image: "amir20/dozzle",
|
|
1301
|
-
puid: 0,
|
|
1302
|
-
pgid: 0,
|
|
1303
|
-
volumes: () => ["/var/run/docker.sock:/var/run/docker.sock"]
|
|
1304
|
-
},
|
|
1305
|
-
"uptime-kuma": {
|
|
1306
|
-
id: "uptime-kuma",
|
|
1307
|
-
name: "Uptime Kuma",
|
|
1308
|
-
description: "Self-hosted monitoring tool",
|
|
1309
|
-
category: "monitoring",
|
|
1310
|
-
defaultPort: 3001,
|
|
1311
|
-
image: "louislam/uptime-kuma:1",
|
|
1312
|
-
puid: 0,
|
|
1313
|
-
pgid: 0,
|
|
1314
|
-
volumes: (root) => [
|
|
1315
|
-
`${root}/config/uptime-kuma:/app/data`,
|
|
1316
|
-
"/var/run/docker.sock:/var/run/docker.sock"
|
|
1317
|
-
],
|
|
1318
|
-
homepage: { icon: "uptime-kuma.png", widget: "uptimekuma" },
|
|
1319
|
-
autoSetup: {
|
|
1320
|
-
type: "full",
|
|
1321
|
-
description: "Create admin user, add monitors for enabled apps"
|
|
1322
|
-
},
|
|
1323
|
-
logVolume: "/app/data/logs"
|
|
1324
|
-
},
|
|
1325
|
-
traefik: {
|
|
1326
|
-
id: "traefik",
|
|
1327
|
-
name: "Traefik",
|
|
1328
|
-
description: "Reverse proxy and load balancer",
|
|
1329
|
-
category: "infrastructure",
|
|
1330
|
-
defaultPort: 80,
|
|
1331
|
-
internalPort: 80,
|
|
1332
|
-
image: "traefik:latest",
|
|
1333
|
-
puid: 0,
|
|
1334
|
-
pgid: 0,
|
|
1335
|
-
volumes: (root) => [
|
|
1336
|
-
`${root}/config/traefik:/etc/traefik`,
|
|
1337
|
-
`${root}/config/traefik/letsencrypt:/letsencrypt`,
|
|
1338
|
-
"/var/run/docker.sock:/var/run/docker.sock:ro"
|
|
1339
|
-
],
|
|
1340
|
-
secondaryPorts: ["8083:8080"],
|
|
1341
|
-
secrets: [
|
|
1342
|
-
{
|
|
1343
|
-
name: "CLOUDFLARE_DNS_ZONE",
|
|
1344
|
-
description: "Root Domain (e.g. example.com)",
|
|
1345
|
-
required: true
|
|
1346
|
-
}
|
|
1347
|
-
],
|
|
1348
|
-
homepage: { icon: "traefik.png", widget: "traefik" },
|
|
1349
|
-
logVolume: "/etc/traefik/logs"
|
|
1350
|
-
},
|
|
1351
|
-
caddy: {
|
|
1352
|
-
id: "caddy",
|
|
1353
|
-
name: "Caddy",
|
|
1354
|
-
description: "Web server with automatic HTTPS and reverse proxy",
|
|
1355
|
-
category: "infrastructure",
|
|
1356
|
-
defaultPort: 80,
|
|
1357
|
-
internalPort: 80,
|
|
1358
|
-
secondaryPorts: ["443:443"],
|
|
1359
|
-
image: "caddy:latest",
|
|
1360
|
-
puid: 0,
|
|
1361
|
-
pgid: 0,
|
|
1362
|
-
volumes: (root) => [
|
|
1363
|
-
`${root}/config/caddy/Caddyfile:/etc/caddy/Caddyfile`,
|
|
1364
|
-
`${root}/config/caddy/data:/data`,
|
|
1365
|
-
`${root}/config/caddy/config:/config`
|
|
1366
|
-
],
|
|
1367
|
-
homepage: { icon: "caddy.png" },
|
|
1368
|
-
logVolume: "/data/logs"
|
|
1369
|
-
},
|
|
1370
|
-
cloudflared: {
|
|
1371
|
-
id: "cloudflared",
|
|
1372
|
-
name: "Cloudflared",
|
|
1373
|
-
description: "Cloudflare Tunnel for secure external access without port forwarding",
|
|
1374
|
-
category: "infrastructure",
|
|
1375
|
-
defaultPort: 0,
|
|
1376
|
-
image: "cloudflare/cloudflared:latest",
|
|
1377
|
-
puid: 0,
|
|
1378
|
-
pgid: 0,
|
|
1379
|
-
volumes: () => [],
|
|
1380
|
-
environment: {
|
|
1381
|
-
TUNNEL_TOKEN: "${CLOUDFLARE_TUNNEL_TOKEN}"
|
|
1382
|
-
},
|
|
1383
|
-
command: "tunnel run",
|
|
1384
|
-
dependsOn: ["traefik"],
|
|
1385
|
-
secrets: [
|
|
1386
|
-
{
|
|
1387
|
-
name: "CLOUDFLARE_API_TOKEN",
|
|
1388
|
-
description: "Cloudflare API Token (for automated tunnel setup via Menu)",
|
|
1389
|
-
required: false,
|
|
1390
|
-
mask: true
|
|
1391
|
-
},
|
|
1392
|
-
{
|
|
1393
|
-
name: "CLOUDFLARE_TUNNEL_TOKEN",
|
|
1394
|
-
description: "Cloudflare Tunnel Token (auto-generated or from Zero Trust)",
|
|
1395
|
-
required: true,
|
|
1396
|
-
mask: true
|
|
1397
|
-
}
|
|
1398
|
-
],
|
|
1399
|
-
homepage: { icon: "cloudflare-zero-trust.png", widget: "cloudflared" }
|
|
1400
|
-
},
|
|
1401
|
-
"traefik-certs-dumper": {
|
|
1402
|
-
id: "traefik-certs-dumper",
|
|
1403
|
-
name: "Traefik Certs Dumper",
|
|
1404
|
-
description: "Extracts certificates from Traefik",
|
|
1405
|
-
category: "infrastructure",
|
|
1406
|
-
defaultPort: 0,
|
|
1407
|
-
image: "ldez/traefik-certs-dumper:latest",
|
|
1408
|
-
puid: 0,
|
|
1409
|
-
pgid: 0,
|
|
1410
|
-
volumes: (root) => [
|
|
1411
|
-
`${root}/config/traefik/letsencrypt:/traefik:ro`,
|
|
1412
|
-
`${root}/config/traefik/certs:/output`
|
|
1413
|
-
],
|
|
1414
|
-
dependsOn: ["traefik"]
|
|
1415
|
-
},
|
|
1416
|
-
crowdsec: {
|
|
1417
|
-
id: "crowdsec",
|
|
1418
|
-
name: "CrowdSec",
|
|
1419
|
-
description: "Intrusion prevention system",
|
|
1420
|
-
category: "infrastructure",
|
|
1421
|
-
defaultPort: 8080,
|
|
1422
|
-
image: "crowdsecurity/crowdsec:latest",
|
|
1423
|
-
puid: 0,
|
|
1424
|
-
pgid: 0,
|
|
1425
|
-
volumes: (root) => [
|
|
1426
|
-
`${root}/config/crowdsec:/etc/crowdsec`,
|
|
1427
|
-
"/var/run/docker.sock:/var/run/docker.sock:ro"
|
|
1428
|
-
],
|
|
1429
|
-
homepage: { icon: "crowdsec.png", widget: "crowdsec" }
|
|
1430
|
-
},
|
|
1431
|
-
headscale: {
|
|
1432
|
-
id: "headscale",
|
|
1433
|
-
name: "Headscale",
|
|
1434
|
-
description: "Open-source Tailscale control server",
|
|
1435
|
-
category: "infrastructure",
|
|
1436
|
-
defaultPort: 8084,
|
|
1437
|
-
image: "headscale/headscale:latest",
|
|
1438
|
-
puid: 0,
|
|
1439
|
-
pgid: 0,
|
|
1440
|
-
volumes: (root) => [
|
|
1441
|
-
`${root}/config/headscale:/etc/headscale`,
|
|
1442
|
-
`${root}/config/headscale/data:/var/lib/headscale`
|
|
1443
|
-
],
|
|
1444
|
-
homepage: { icon: "headscale.png", widget: "headscale" }
|
|
1445
|
-
},
|
|
1446
|
-
headplane: {
|
|
1447
|
-
id: "headplane",
|
|
1448
|
-
name: "Headplane",
|
|
1449
|
-
description: "Headscale web UI",
|
|
1450
|
-
category: "infrastructure",
|
|
1451
|
-
defaultPort: 3000,
|
|
1452
|
-
image: "ghcr.io/tale/headplane:latest",
|
|
1453
|
-
puid: 0,
|
|
1454
|
-
pgid: 0,
|
|
1455
|
-
volumes: (root) => [`${root}/config/headplane:/config`],
|
|
1456
|
-
dependsOn: ["headscale"]
|
|
1457
|
-
},
|
|
1458
|
-
tailscale: {
|
|
1459
|
-
id: "tailscale",
|
|
1460
|
-
name: "Tailscale",
|
|
1461
|
-
description: "VPN mesh network client",
|
|
1462
|
-
category: "infrastructure",
|
|
1463
|
-
defaultPort: 0,
|
|
1464
|
-
image: "tailscale/tailscale:latest",
|
|
1465
|
-
puid: 0,
|
|
1466
|
-
pgid: 0,
|
|
1467
|
-
cap_add: ["NET_ADMIN"],
|
|
1468
|
-
devices: ["/dev/net/tun:/dev/net/tun"],
|
|
1469
|
-
volumes: (root) => [`${root}/config/tailscale:/var/lib/tailscale`],
|
|
1470
|
-
secrets: [
|
|
1471
|
-
{
|
|
1472
|
-
name: "TAILSCALE_AUTHKEY",
|
|
1473
|
-
description: "Tailscale Auth Key",
|
|
1474
|
-
required: true,
|
|
1475
|
-
mask: true
|
|
1476
|
-
}
|
|
1477
|
-
],
|
|
1478
|
-
homepage: { icon: "tailscale.png", widget: "tailscale" }
|
|
1479
|
-
},
|
|
1480
|
-
authentik: {
|
|
1481
|
-
id: "authentik",
|
|
1482
|
-
name: "Authentik",
|
|
1483
|
-
description: "Identity provider and SSO (Server)",
|
|
1484
|
-
category: "infrastructure",
|
|
1485
|
-
defaultPort: 9001,
|
|
1486
|
-
image: "ghcr.io/goauthentik/server:latest",
|
|
1487
|
-
puid: 0,
|
|
1488
|
-
pgid: 13000,
|
|
1489
|
-
volumes: (root) => [
|
|
1490
|
-
`${root}/config/authentik/media:/media`,
|
|
1491
|
-
`${root}/config/authentik/templates:/templates`
|
|
1492
|
-
],
|
|
1493
|
-
environment: {
|
|
1494
|
-
AUTHENTIK_REDIS__HOST: "valkey",
|
|
1495
|
-
AUTHENTIK_POSTGRESQL__HOST: "postgresql",
|
|
1496
|
-
AUTHENTIK_POSTGRESQL__NAME: "authentik",
|
|
1497
|
-
AUTHENTIK_POSTGRESQL__USER: "${USERNAME_POSTGRESQL}",
|
|
1498
|
-
AUTHENTIK_POSTGRESQL__PASSWORD: "${PASSWORD_POSTGRESQL}",
|
|
1499
|
-
AUTHENTIK_SECRET_KEY: "${AUTHENTIK_SECRET_KEY}"
|
|
1500
|
-
},
|
|
1501
|
-
dependsOn: ["postgresql", "valkey", "authentik-worker"],
|
|
1502
|
-
secrets: [
|
|
1503
|
-
{
|
|
1504
|
-
name: "AUTHENTIK_SECRET_KEY",
|
|
1505
|
-
description: "Authentik Secret Key",
|
|
1506
|
-
required: true,
|
|
1507
|
-
mask: true,
|
|
1508
|
-
generate: true
|
|
1509
|
-
},
|
|
1510
|
-
{
|
|
1511
|
-
name: "USERNAME_POSTGRESQL",
|
|
1512
|
-
description: "Postgres Username",
|
|
1513
|
-
required: true,
|
|
1514
|
-
default: "postgres"
|
|
1515
|
-
},
|
|
1516
|
-
{
|
|
1517
|
-
name: "PASSWORD_POSTGRESQL",
|
|
1518
|
-
description: "Postgres Password",
|
|
1519
|
-
required: true,
|
|
1520
|
-
mask: true
|
|
1521
|
-
}
|
|
1522
|
-
],
|
|
1523
|
-
homepage: { icon: "authentik.png", widget: "authentik" }
|
|
1524
|
-
},
|
|
1525
|
-
"authentik-worker": {
|
|
1526
|
-
id: "authentik-worker",
|
|
1527
|
-
name: "Authentik Worker",
|
|
1528
|
-
description: "Identity provider background worker",
|
|
1529
|
-
category: "infrastructure",
|
|
1530
|
-
defaultPort: 0,
|
|
1531
|
-
image: "ghcr.io/goauthentik/server:latest",
|
|
1532
|
-
puid: 0,
|
|
1533
|
-
pgid: 13000,
|
|
1534
|
-
volumes: (root) => [
|
|
1535
|
-
`${root}/config/authentik/media:/media`,
|
|
1536
|
-
`${root}/config/authentik/templates:/templates`,
|
|
1537
|
-
`${root}/config/authentik/certs:/certs`,
|
|
1538
|
-
"/var/run/docker.sock:/var/run/docker.sock"
|
|
1539
|
-
],
|
|
1540
|
-
environment: {
|
|
1541
|
-
AUTHENTIK_REDIS__HOST: "valkey",
|
|
1542
|
-
AUTHENTIK_POSTGRESQL__HOST: "postgresql",
|
|
1543
|
-
AUTHENTIK_POSTGRESQL__NAME: "authentik",
|
|
1544
|
-
AUTHENTIK_POSTGRESQL__USER: "${USERNAME_POSTGRESQL}",
|
|
1545
|
-
AUTHENTIK_POSTGRESQL__PASSWORD: "${PASSWORD_POSTGRESQL}",
|
|
1546
|
-
AUTHENTIK_SECRET_KEY: "${AUTHENTIK_SECRET_KEY}"
|
|
1547
|
-
},
|
|
1548
|
-
dependsOn: ["postgresql", "valkey"]
|
|
1549
|
-
},
|
|
1550
|
-
postgresql: {
|
|
1551
|
-
id: "postgresql",
|
|
1552
|
-
name: "PostgreSQL",
|
|
1553
|
-
description: "Database server",
|
|
1554
|
-
category: "infrastructure",
|
|
1555
|
-
defaultPort: 5432,
|
|
1556
|
-
image: "docker.io/library/postgres:latest",
|
|
1557
|
-
puid: 0,
|
|
1558
|
-
pgid: 13000,
|
|
1559
|
-
volumes: (root) => [`${root}/config/postgresql:/var/lib/postgresql/data`],
|
|
1560
|
-
environment: {
|
|
1561
|
-
POSTGRES_USER: "${USERNAME_POSTGRESQL}",
|
|
1562
|
-
POSTGRES_PASSWORD: "${PASSWORD_POSTGRESQL}",
|
|
1563
|
-
POSTGRES_DB: "authentik"
|
|
1564
|
-
},
|
|
1565
|
-
secrets: [
|
|
1566
|
-
{
|
|
1567
|
-
name: "USERNAME_POSTGRESQL",
|
|
1568
|
-
description: "PostgreSQL Username",
|
|
1569
|
-
required: true,
|
|
1570
|
-
default: "postgres"
|
|
1571
|
-
},
|
|
1572
|
-
{
|
|
1573
|
-
name: "PASSWORD_POSTGRESQL",
|
|
1574
|
-
description: "PostgreSQL Password",
|
|
1575
|
-
required: true,
|
|
1576
|
-
mask: true
|
|
1577
|
-
}
|
|
1578
|
-
]
|
|
1579
|
-
},
|
|
1580
|
-
valkey: {
|
|
1581
|
-
id: "valkey",
|
|
1582
|
-
name: "Valkey",
|
|
1583
|
-
description: "Redis-compatible key-value store",
|
|
1584
|
-
category: "infrastructure",
|
|
1585
|
-
defaultPort: 6379,
|
|
1586
|
-
image: "valkey/valkey:alpine",
|
|
1587
|
-
puid: 0,
|
|
1588
|
-
pgid: 13000,
|
|
1589
|
-
volumes: (root) => [`${root}/config/valkey:/data`]
|
|
1590
|
-
}
|
|
1591
|
-
};
|
|
1592
|
-
});
|
|
1593
|
-
|
|
1594
355
|
// src/utils/env.ts
|
|
1595
|
-
var exports_env = {};
|
|
1596
|
-
__export(exports_env, {
|
|
1597
|
-
writeEnvSync: () => writeEnvSync,
|
|
1598
|
-
updateEnv: () => updateEnv,
|
|
1599
|
-
serializeEnv: () => serializeEnv,
|
|
1600
|
-
readEnvSync: () => readEnvSync,
|
|
1601
|
-
readEnv: () => readEnv,
|
|
1602
|
-
parseEnvFile: () => parseEnvFile,
|
|
1603
|
-
getLocalIp: () => getLocalIp,
|
|
1604
|
-
getEnvValue: () => getEnvValue,
|
|
1605
|
-
getEnvPath: () => getEnvPath
|
|
1606
|
-
});
|
|
1607
356
|
import { existsSync as existsSync3, readFileSync, writeFileSync as writeFileSync2 } from "fs";
|
|
1608
357
|
import { readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
|
|
1609
358
|
import { networkInterfaces } from "os";
|
|
@@ -1678,9 +427,6 @@ async function updateEnv(updates) {
|
|
|
1678
427
|
const content = serializeEnv(merged);
|
|
1679
428
|
await writeFile2(envPath, content, "utf-8");
|
|
1680
429
|
}
|
|
1681
|
-
function getEnvValue(key) {
|
|
1682
|
-
return readEnvSync()[key];
|
|
1683
|
-
}
|
|
1684
430
|
var init_env = __esm(() => {
|
|
1685
431
|
init_manager();
|
|
1686
432
|
});
|
|
@@ -11894,8 +10640,1191 @@ var CATEGORY_ORDER = [
|
|
|
11894
10640
|
{ id: "infrastructure", short: "Infra" }
|
|
11895
10641
|
];
|
|
11896
10642
|
|
|
10643
|
+
// src/utils/arch.ts
|
|
10644
|
+
function getSystemArch() {
|
|
10645
|
+
const arch = process.arch;
|
|
10646
|
+
switch (arch) {
|
|
10647
|
+
case "x64":
|
|
10648
|
+
case "ia32":
|
|
10649
|
+
return "x64";
|
|
10650
|
+
case "arm64":
|
|
10651
|
+
return "arm64";
|
|
10652
|
+
case "arm":
|
|
10653
|
+
return "arm32";
|
|
10654
|
+
default:
|
|
10655
|
+
return "x64";
|
|
10656
|
+
}
|
|
10657
|
+
}
|
|
10658
|
+
function getArchWarning(app, arch) {
|
|
10659
|
+
const systemArch = arch ?? getSystemArch();
|
|
10660
|
+
if (!app.arch) {
|
|
10661
|
+
return null;
|
|
10662
|
+
}
|
|
10663
|
+
if (app.arch.deprecated?.includes(systemArch)) {
|
|
10664
|
+
return app.arch.warning || `${app.name} has deprecated support for ${systemArch}`;
|
|
10665
|
+
}
|
|
10666
|
+
if (app.arch.supported && !app.arch.supported.includes(systemArch)) {
|
|
10667
|
+
return `${app.name} does not support ${systemArch} architecture`;
|
|
10668
|
+
}
|
|
10669
|
+
return null;
|
|
10670
|
+
}
|
|
10671
|
+
|
|
10672
|
+
// src/apps/registry.ts
|
|
10673
|
+
var APPS = {
|
|
10674
|
+
radarr: {
|
|
10675
|
+
id: "radarr",
|
|
10676
|
+
name: "Radarr",
|
|
10677
|
+
description: "Movie collection manager",
|
|
10678
|
+
category: "servarr",
|
|
10679
|
+
defaultPort: 7878,
|
|
10680
|
+
image: "lscr.io/linuxserver/radarr:latest",
|
|
10681
|
+
puid: 13002,
|
|
10682
|
+
pgid: 13000,
|
|
10683
|
+
volumes: (root) => [`${root}/config/radarr:/config`, `${root}/data:/data`],
|
|
10684
|
+
trashGuide: "docs/Radarr/",
|
|
10685
|
+
apiKeyMeta: {
|
|
10686
|
+
configFile: "config.xml",
|
|
10687
|
+
parser: "regex",
|
|
10688
|
+
selector: "<ApiKey>(.*?)</ApiKey>"
|
|
10689
|
+
},
|
|
10690
|
+
rootFolder: {
|
|
10691
|
+
path: "/data/media/movies",
|
|
10692
|
+
apiVersion: "v3"
|
|
10693
|
+
},
|
|
10694
|
+
prowlarrCategoryIds: [2000, 2010, 2020, 2030, 2040, 2045, 2050, 2060, 2070, 2080, 2090],
|
|
10695
|
+
homepage: { icon: "radarr.png", widget: "radarr" },
|
|
10696
|
+
logVolume: "/config/logs"
|
|
10697
|
+
},
|
|
10698
|
+
sonarr: {
|
|
10699
|
+
id: "sonarr",
|
|
10700
|
+
name: "Sonarr",
|
|
10701
|
+
description: "TV series collection manager",
|
|
10702
|
+
category: "servarr",
|
|
10703
|
+
defaultPort: 8989,
|
|
10704
|
+
image: "lscr.io/linuxserver/sonarr:latest",
|
|
10705
|
+
puid: 13001,
|
|
10706
|
+
pgid: 13000,
|
|
10707
|
+
volumes: (root) => [`${root}/config/sonarr:/config`, `${root}/data:/data`],
|
|
10708
|
+
trashGuide: "docs/Sonarr/",
|
|
10709
|
+
apiKeyMeta: {
|
|
10710
|
+
configFile: "config.xml",
|
|
10711
|
+
parser: "regex",
|
|
10712
|
+
selector: "<ApiKey>(.*?)</ApiKey>"
|
|
10713
|
+
},
|
|
10714
|
+
rootFolder: {
|
|
10715
|
+
path: "/data/media/tv",
|
|
10716
|
+
apiVersion: "v3"
|
|
10717
|
+
},
|
|
10718
|
+
prowlarrCategoryIds: [5000, 5010, 5020, 5030, 5040, 5045, 5050, 5060, 5070, 5080, 5090],
|
|
10719
|
+
homepage: { icon: "sonarr.png", widget: "sonarr" },
|
|
10720
|
+
logVolume: "/config/logs"
|
|
10721
|
+
},
|
|
10722
|
+
lidarr: {
|
|
10723
|
+
id: "lidarr",
|
|
10724
|
+
name: "Lidarr",
|
|
10725
|
+
description: "Music collection manager",
|
|
10726
|
+
category: "servarr",
|
|
10727
|
+
defaultPort: 8686,
|
|
10728
|
+
image: "lscr.io/linuxserver/lidarr:latest",
|
|
10729
|
+
puid: 13003,
|
|
10730
|
+
pgid: 13000,
|
|
10731
|
+
volumes: (root) => [`${root}/config/lidarr:/config`, `${root}/data:/data`],
|
|
10732
|
+
apiKeyMeta: {
|
|
10733
|
+
configFile: "config.xml",
|
|
10734
|
+
parser: "regex",
|
|
10735
|
+
selector: "<ApiKey>(.*?)</ApiKey>"
|
|
10736
|
+
},
|
|
10737
|
+
rootFolder: {
|
|
10738
|
+
path: "/data/media/music",
|
|
10739
|
+
apiVersion: "v1"
|
|
10740
|
+
},
|
|
10741
|
+
prowlarrCategoryIds: [3000, 3010, 3020, 3030, 3040, 3050, 3060],
|
|
10742
|
+
homepage: { icon: "lidarr.png", widget: "lidarr" },
|
|
10743
|
+
logVolume: "/config/logs"
|
|
10744
|
+
},
|
|
10745
|
+
readarr: {
|
|
10746
|
+
id: "readarr",
|
|
10747
|
+
name: "Readarr",
|
|
10748
|
+
description: "Book collection manager",
|
|
10749
|
+
category: "servarr",
|
|
10750
|
+
defaultPort: 8787,
|
|
10751
|
+
image: "lscr.io/linuxserver/readarr:develop",
|
|
10752
|
+
puid: 13004,
|
|
10753
|
+
pgid: 13000,
|
|
10754
|
+
volumes: (root) => [`${root}/config/readarr:/config`, `${root}/data:/data`],
|
|
10755
|
+
apiKeyMeta: {
|
|
10756
|
+
configFile: "config.xml",
|
|
10757
|
+
parser: "regex",
|
|
10758
|
+
selector: "<ApiKey>(.*?)</ApiKey>"
|
|
10759
|
+
},
|
|
10760
|
+
rootFolder: {
|
|
10761
|
+
path: "/data/media/books",
|
|
10762
|
+
apiVersion: "v1"
|
|
10763
|
+
},
|
|
10764
|
+
prowlarrCategoryIds: [7000, 7010, 7020, 7030, 7040, 7050, 7060],
|
|
10765
|
+
arch: {
|
|
10766
|
+
deprecated: ["arm64", "arm32"],
|
|
10767
|
+
warning: "Readarr is deprecated - no ARM64 support (project abandoned by upstream)"
|
|
10768
|
+
},
|
|
10769
|
+
homepage: { icon: "readarr.png", widget: "readarr" },
|
|
10770
|
+
logVolume: "/config/logs"
|
|
10771
|
+
},
|
|
10772
|
+
bazarr: {
|
|
10773
|
+
id: "bazarr",
|
|
10774
|
+
name: "Bazarr",
|
|
10775
|
+
description: "Subtitle manager for Sonarr/Radarr",
|
|
10776
|
+
category: "servarr",
|
|
10777
|
+
defaultPort: 6767,
|
|
10778
|
+
image: "lscr.io/linuxserver/bazarr:latest",
|
|
10779
|
+
puid: 13013,
|
|
10780
|
+
pgid: 13000,
|
|
10781
|
+
volumes: (root) => [`${root}/config/bazarr:/config`, `${root}/data/media:/data/media`],
|
|
10782
|
+
dependsOn: ["sonarr", "radarr"],
|
|
10783
|
+
trashGuide: "docs/Bazarr/",
|
|
10784
|
+
apiKeyMeta: {
|
|
10785
|
+
configFile: "config/config.yaml",
|
|
10786
|
+
parser: "yaml",
|
|
10787
|
+
selector: "auth.apikey"
|
|
10788
|
+
},
|
|
10789
|
+
homepage: { icon: "bazarr.png", widget: "bazarr" },
|
|
10790
|
+
logVolume: "/config/log"
|
|
10791
|
+
},
|
|
10792
|
+
mylar3: {
|
|
10793
|
+
id: "mylar3",
|
|
10794
|
+
name: "Mylar3",
|
|
10795
|
+
description: "Comic book collection manager",
|
|
10796
|
+
category: "servarr",
|
|
10797
|
+
defaultPort: 8090,
|
|
10798
|
+
image: "lscr.io/linuxserver/mylar3:latest",
|
|
10799
|
+
puid: 13005,
|
|
10800
|
+
pgid: 13000,
|
|
10801
|
+
volumes: (root) => [`${root}/config/mylar3:/config`, `${root}/data:/data`],
|
|
10802
|
+
apiKeyMeta: {
|
|
10803
|
+
configFile: "mylar/config.ini",
|
|
10804
|
+
parser: "ini",
|
|
10805
|
+
section: "API",
|
|
10806
|
+
selector: "api_key",
|
|
10807
|
+
enabledKey: "api_enabled",
|
|
10808
|
+
generateIfMissing: true
|
|
10809
|
+
},
|
|
10810
|
+
prowlarrCategoryIds: [7030],
|
|
10811
|
+
homepage: { icon: "mylar.png", widget: "mylar" },
|
|
10812
|
+
logVolume: "/app/mylar/logs"
|
|
10813
|
+
},
|
|
10814
|
+
whisparr: {
|
|
10815
|
+
id: "whisparr",
|
|
10816
|
+
name: "Whisparr",
|
|
10817
|
+
description: "Adult media collection manager",
|
|
10818
|
+
category: "servarr",
|
|
10819
|
+
defaultPort: 6969,
|
|
10820
|
+
image: "ghcr.io/hotio/whisparr:nightly",
|
|
10821
|
+
puid: 13015,
|
|
10822
|
+
pgid: 13000,
|
|
10823
|
+
volumes: (root) => [`${root}/config/whisparr:/config`, `${root}/data:/data`],
|
|
10824
|
+
apiKeyMeta: {
|
|
10825
|
+
configFile: "config.xml",
|
|
10826
|
+
parser: "regex",
|
|
10827
|
+
selector: "<ApiKey>(.*?)</ApiKey>"
|
|
10828
|
+
},
|
|
10829
|
+
rootFolder: {
|
|
10830
|
+
path: "/data/media/adult",
|
|
10831
|
+
apiVersion: "v3"
|
|
10832
|
+
},
|
|
10833
|
+
prowlarrCategoryIds: [6000, 6010, 6020, 6030, 6040, 6045, 6050, 6060, 6070, 6080, 6090],
|
|
10834
|
+
homepage: { icon: "whisparr.png", widget: "sonarr" },
|
|
10835
|
+
logVolume: "/config/logs"
|
|
10836
|
+
},
|
|
10837
|
+
audiobookshelf: {
|
|
10838
|
+
id: "audiobookshelf",
|
|
10839
|
+
name: "Audiobookshelf",
|
|
10840
|
+
description: "Audiobook and podcast server",
|
|
10841
|
+
category: "servarr",
|
|
10842
|
+
defaultPort: 13378,
|
|
10843
|
+
image: "ghcr.io/advplyr/audiobookshelf:latest",
|
|
10844
|
+
puid: 13014,
|
|
10845
|
+
pgid: 13000,
|
|
10846
|
+
volumes: (root) => [
|
|
10847
|
+
`${root}/config/audiobookshelf:/config`,
|
|
10848
|
+
`${root}/data/media/audiobooks:/audiobooks`,
|
|
10849
|
+
`${root}/data/media/podcasts:/podcasts`,
|
|
10850
|
+
`${root}/data/media/audiobookshelf-metadata:/metadata`
|
|
10851
|
+
],
|
|
10852
|
+
homepage: { icon: "audiobookshelf.png", widget: "audiobookshelf" },
|
|
10853
|
+
logVolume: "/config/metadata/logs"
|
|
10854
|
+
},
|
|
10855
|
+
prowlarr: {
|
|
10856
|
+
id: "prowlarr",
|
|
10857
|
+
name: "Prowlarr",
|
|
10858
|
+
description: "Indexer manager for *arr apps",
|
|
10859
|
+
category: "indexer",
|
|
10860
|
+
defaultPort: 9696,
|
|
10861
|
+
image: "lscr.io/linuxserver/prowlarr:develop",
|
|
10862
|
+
puid: 13006,
|
|
10863
|
+
pgid: 13000,
|
|
10864
|
+
volumes: (root) => [`${root}/config/prowlarr:/config`],
|
|
10865
|
+
trashGuide: "docs/Prowlarr/",
|
|
10866
|
+
apiKeyMeta: {
|
|
10867
|
+
configFile: "config.xml",
|
|
10868
|
+
parser: "regex",
|
|
10869
|
+
selector: "<ApiKey>(.*?)</ApiKey>"
|
|
10870
|
+
},
|
|
10871
|
+
homepage: { icon: "prowlarr.png", widget: "prowlarr" },
|
|
10872
|
+
logVolume: "/config/logs"
|
|
10873
|
+
},
|
|
10874
|
+
jackett: {
|
|
10875
|
+
id: "jackett",
|
|
10876
|
+
name: "Jackett",
|
|
10877
|
+
description: "Alternative indexer manager",
|
|
10878
|
+
category: "indexer",
|
|
10879
|
+
defaultPort: 9117,
|
|
10880
|
+
image: "lscr.io/linuxserver/jackett:latest",
|
|
10881
|
+
puid: 13008,
|
|
10882
|
+
pgid: 13000,
|
|
10883
|
+
volumes: (root) => [`${root}/config/jackett:/config`],
|
|
10884
|
+
apiKeyMeta: {
|
|
10885
|
+
configFile: "Jackett/ServerConfig.json",
|
|
10886
|
+
parser: "json",
|
|
10887
|
+
selector: "APIKey"
|
|
10888
|
+
},
|
|
10889
|
+
homepage: { icon: "jackett.png", widget: "jackett" },
|
|
10890
|
+
logVolume: "/config/logs"
|
|
10891
|
+
},
|
|
10892
|
+
flaresolverr: {
|
|
10893
|
+
id: "flaresolverr",
|
|
10894
|
+
name: "FlareSolverr",
|
|
10895
|
+
description: "Cloudflare bypass proxy",
|
|
10896
|
+
category: "indexer",
|
|
10897
|
+
defaultPort: 8191,
|
|
10898
|
+
image: "ghcr.io/flaresolverr/flaresolverr:latest",
|
|
10899
|
+
puid: 0,
|
|
10900
|
+
pgid: 0,
|
|
10901
|
+
volumes: () => [],
|
|
10902
|
+
environment: {
|
|
10903
|
+
LOG_LEVEL: "info",
|
|
10904
|
+
LOG_HTML: "false",
|
|
10905
|
+
CAPTCHA_SOLVER: "none"
|
|
10906
|
+
},
|
|
10907
|
+
homepage: {
|
|
10908
|
+
icon: "flaresolverr.png",
|
|
10909
|
+
widget: "customapi",
|
|
10910
|
+
widgetFields: {
|
|
10911
|
+
url: "http://flaresolverr:8191",
|
|
10912
|
+
mappings: JSON.stringify([
|
|
10913
|
+
{ field: "msg", label: "Status" },
|
|
10914
|
+
{ field: "version", label: "Version" }
|
|
10915
|
+
])
|
|
10916
|
+
}
|
|
10917
|
+
}
|
|
10918
|
+
},
|
|
10919
|
+
qbittorrent: {
|
|
10920
|
+
id: "qbittorrent",
|
|
10921
|
+
name: "qBittorrent",
|
|
10922
|
+
description: "BitTorrent client",
|
|
10923
|
+
category: "downloader",
|
|
10924
|
+
defaultPort: 8080,
|
|
10925
|
+
image: "lscr.io/linuxserver/qbittorrent:latest",
|
|
10926
|
+
puid: 13007,
|
|
10927
|
+
pgid: 13000,
|
|
10928
|
+
volumes: (root) => [`${root}/config/qbittorrent:/config`, `${root}/data:/data`],
|
|
10929
|
+
environment: { WEBUI_PORT: "8080" },
|
|
10930
|
+
secrets: [
|
|
10931
|
+
{
|
|
10932
|
+
name: "USERNAME_QBITTORRENT",
|
|
10933
|
+
description: "Username for qBittorrent WebUI",
|
|
10934
|
+
required: false,
|
|
10935
|
+
default: "admin"
|
|
10936
|
+
},
|
|
10937
|
+
{
|
|
10938
|
+
name: "PASSWORD_QBITTORRENT",
|
|
10939
|
+
description: "Password for qBittorrent WebUI",
|
|
10940
|
+
required: false,
|
|
10941
|
+
mask: true
|
|
10942
|
+
}
|
|
10943
|
+
],
|
|
10944
|
+
trashGuide: "docs/Downloaders/qBittorrent/",
|
|
10945
|
+
homepage: { icon: "qbittorrent.png", widget: "qbittorrent" },
|
|
10946
|
+
logVolume: "/config/qBittorrent/logs"
|
|
10947
|
+
},
|
|
10948
|
+
sabnzbd: {
|
|
10949
|
+
id: "sabnzbd",
|
|
10950
|
+
name: "SABnzbd",
|
|
10951
|
+
description: "Usenet downloader",
|
|
10952
|
+
category: "downloader",
|
|
10953
|
+
defaultPort: 8081,
|
|
10954
|
+
image: "lscr.io/linuxserver/sabnzbd:latest",
|
|
10955
|
+
puid: 13011,
|
|
10956
|
+
pgid: 13000,
|
|
10957
|
+
volumes: (root) => [`${root}/config/sabnzbd:/config`, `${root}/data:/data`],
|
|
10958
|
+
trashGuide: "docs/Downloaders/SABnzbd/",
|
|
10959
|
+
apiKeyMeta: {
|
|
10960
|
+
configFile: "sabnzbd.ini",
|
|
10961
|
+
parser: "regex",
|
|
10962
|
+
selector: "api_key\\s*=\\s*(.+)"
|
|
10963
|
+
},
|
|
10964
|
+
homepage: { icon: "sabnzbd.png", widget: "sabnzbd" },
|
|
10965
|
+
logVolume: "/config/logs"
|
|
10966
|
+
},
|
|
10967
|
+
slskd: {
|
|
10968
|
+
id: "slskd",
|
|
10969
|
+
name: "Slskd",
|
|
10970
|
+
description: "Soulseek client for music downloads",
|
|
10971
|
+
category: "downloader",
|
|
10972
|
+
defaultPort: 5030,
|
|
10973
|
+
image: "slskd/slskd",
|
|
10974
|
+
puid: 0,
|
|
10975
|
+
pgid: 0,
|
|
10976
|
+
useDockerUser: true,
|
|
10977
|
+
volumes: (root) => [`${root}/config/slskd:/app`, `${root}/data:/data`],
|
|
10978
|
+
secondaryPorts: ["5031:5031", "50300:50300"],
|
|
10979
|
+
environment: {
|
|
10980
|
+
SLSKD_REMOTE_CONFIGURATION: "true",
|
|
10981
|
+
SLSKD_USERNAME: "${USERNAME_GLOBAL}",
|
|
10982
|
+
SLSKD_PASSWORD: "${PASSWORD_GLOBAL}",
|
|
10983
|
+
SLSKD_SLSK_USERNAME: "${USERNAME_SOULSEEK}",
|
|
10984
|
+
SLSKD_SLSK_PASSWORD: "${PASSWORD_SOULSEEK}"
|
|
10985
|
+
},
|
|
10986
|
+
secrets: [
|
|
10987
|
+
{
|
|
10988
|
+
name: "USERNAME_SOULSEEK",
|
|
10989
|
+
description: "Soulseek network username (your Soulseek account)",
|
|
10990
|
+
required: true
|
|
10991
|
+
},
|
|
10992
|
+
{
|
|
10993
|
+
name: "PASSWORD_SOULSEEK",
|
|
10994
|
+
description: "Soulseek network password",
|
|
10995
|
+
required: true,
|
|
10996
|
+
mask: true
|
|
10997
|
+
}
|
|
10998
|
+
],
|
|
10999
|
+
homepage: { icon: "slskd.png", widget: "slskd" },
|
|
11000
|
+
autoSetup: {
|
|
11001
|
+
type: "partial",
|
|
11002
|
+
description: "Generates slskd.yml with API key for Homepage widget and Soularr integration"
|
|
11003
|
+
},
|
|
11004
|
+
logVolume: "/app/logs"
|
|
11005
|
+
},
|
|
11006
|
+
soularr: {
|
|
11007
|
+
id: "soularr",
|
|
11008
|
+
name: "Soularr",
|
|
11009
|
+
description: "Connects Lidarr with Soulseek via Slskd",
|
|
11010
|
+
category: "downloader",
|
|
11011
|
+
defaultPort: 0,
|
|
11012
|
+
image: "mrusse08/soularr:latest",
|
|
11013
|
+
puid: 13017,
|
|
11014
|
+
pgid: 13000,
|
|
11015
|
+
volumes: (root) => [`${root}/data/slskd_downloads:/downloads`, `${root}/config/soularr:/data`],
|
|
11016
|
+
environment: {
|
|
11017
|
+
SCRIPT_INTERVAL: "300"
|
|
11018
|
+
},
|
|
11019
|
+
dependsOn: ["lidarr", "slskd"]
|
|
11020
|
+
},
|
|
11021
|
+
plex: {
|
|
11022
|
+
id: "plex",
|
|
11023
|
+
name: "Plex",
|
|
11024
|
+
description: "Media server with streaming",
|
|
11025
|
+
category: "mediaserver",
|
|
11026
|
+
defaultPort: 32400,
|
|
11027
|
+
image: "lscr.io/linuxserver/plex:latest",
|
|
11028
|
+
puid: 13010,
|
|
11029
|
+
pgid: 13000,
|
|
11030
|
+
volumes: (root) => [`${root}/config/plex:/config`, `${root}/data/media:/data/media`],
|
|
11031
|
+
environment: { VERSION: "docker", PLEX_CLAIM: "${PLEX_CLAIM}" },
|
|
11032
|
+
trashGuide: "docs/Plex/",
|
|
11033
|
+
apiKeyMeta: {
|
|
11034
|
+
configFile: "Library/Application Support/Plex Media Server/Preferences.xml",
|
|
11035
|
+
parser: "regex",
|
|
11036
|
+
selector: 'PlexOnlineToken="([^"]+)"'
|
|
11037
|
+
},
|
|
11038
|
+
homepage: { icon: "plex.png", widget: "plex" },
|
|
11039
|
+
logVolume: "/config/Library/Application Support/Plex Media Server/Logs",
|
|
11040
|
+
autoSetup: {
|
|
11041
|
+
type: "full",
|
|
11042
|
+
description: "Claim server with token, create media libraries",
|
|
11043
|
+
envVars: ["PLEX_CLAIM"]
|
|
11044
|
+
}
|
|
11045
|
+
},
|
|
11046
|
+
jellyfin: {
|
|
11047
|
+
id: "jellyfin",
|
|
11048
|
+
name: "Jellyfin",
|
|
11049
|
+
description: "Free open-source media server",
|
|
11050
|
+
category: "mediaserver",
|
|
11051
|
+
defaultPort: 8096,
|
|
11052
|
+
image: "lscr.io/linuxserver/jellyfin:latest",
|
|
11053
|
+
puid: 0,
|
|
11054
|
+
pgid: 13000,
|
|
11055
|
+
volumes: (root) => [`${root}/config/jellyfin:/config`, `${root}/data/media:/data/media`],
|
|
11056
|
+
homepage: { icon: "jellyfin.png", widget: "jellyfin" },
|
|
11057
|
+
logVolume: "/config/log"
|
|
11058
|
+
},
|
|
11059
|
+
tautulli: {
|
|
11060
|
+
id: "tautulli",
|
|
11061
|
+
name: "Tautulli",
|
|
11062
|
+
description: "Plex monitoring and statistics",
|
|
11063
|
+
category: "mediaserver",
|
|
11064
|
+
defaultPort: 8181,
|
|
11065
|
+
image: "lscr.io/linuxserver/tautulli:latest",
|
|
11066
|
+
puid: 0,
|
|
11067
|
+
pgid: 13000,
|
|
11068
|
+
volumes: (root) => [`${root}/config/tautulli:/config`],
|
|
11069
|
+
dependsOn: ["plex"],
|
|
11070
|
+
apiKeyMeta: {
|
|
11071
|
+
configFile: "config.ini",
|
|
11072
|
+
parser: "regex",
|
|
11073
|
+
selector: "api_key\\s*=\\s*(.+)"
|
|
11074
|
+
},
|
|
11075
|
+
homepage: { icon: "tautulli.png", widget: "tautulli" },
|
|
11076
|
+
autoSetup: {
|
|
11077
|
+
type: "partial",
|
|
11078
|
+
description: "Connect to Plex, enable API",
|
|
11079
|
+
requires: ["plex"]
|
|
11080
|
+
},
|
|
11081
|
+
logVolume: "/config/logs"
|
|
11082
|
+
},
|
|
11083
|
+
tdarr: {
|
|
11084
|
+
id: "tdarr",
|
|
11085
|
+
name: "Tdarr",
|
|
11086
|
+
description: "Audio/video transcoding automation",
|
|
11087
|
+
category: "mediaserver",
|
|
11088
|
+
defaultPort: 8265,
|
|
11089
|
+
image: "ghcr.io/haveagitgat/tdarr:latest",
|
|
11090
|
+
puid: 0,
|
|
11091
|
+
pgid: 13000,
|
|
11092
|
+
volumes: (root) => [
|
|
11093
|
+
`${root}/config/tdarr/server:/app/server`,
|
|
11094
|
+
`${root}/config/tdarr/configs:/app/configs`,
|
|
11095
|
+
`${root}/config/tdarr/logs:/app/logs`,
|
|
11096
|
+
`${root}/data/media:/data`
|
|
11097
|
+
],
|
|
11098
|
+
environment: { serverIP: "0.0.0.0", internalNode: "true" },
|
|
11099
|
+
homepage: { icon: "tdarr.png", widget: "tdarr" },
|
|
11100
|
+
logVolume: "/app/logs"
|
|
11101
|
+
},
|
|
11102
|
+
overseerr: {
|
|
11103
|
+
id: "overseerr",
|
|
11104
|
+
name: "Overseerr",
|
|
11105
|
+
description: "Request management for Plex",
|
|
11106
|
+
category: "request",
|
|
11107
|
+
defaultPort: 5055,
|
|
11108
|
+
image: "sctx/overseerr:latest",
|
|
11109
|
+
puid: 13009,
|
|
11110
|
+
pgid: 13000,
|
|
11111
|
+
volumes: (root) => [`${root}/config/overseerr:/app/config`],
|
|
11112
|
+
dependsOn: ["plex"],
|
|
11113
|
+
apiKeyMeta: {
|
|
11114
|
+
configFile: "settings.json",
|
|
11115
|
+
parser: "json",
|
|
11116
|
+
selector: "main.apiKey"
|
|
11117
|
+
},
|
|
11118
|
+
homepage: { icon: "overseerr.png", widget: "overseerr" },
|
|
11119
|
+
autoSetup: {
|
|
11120
|
+
type: "full",
|
|
11121
|
+
description: "Connect to Plex, configure Radarr/Sonarr",
|
|
11122
|
+
requires: ["plex"]
|
|
11123
|
+
},
|
|
11124
|
+
logVolume: "/app/config/logs"
|
|
11125
|
+
},
|
|
11126
|
+
jellyseerr: {
|
|
11127
|
+
id: "jellyseerr",
|
|
11128
|
+
name: "Jellyseerr",
|
|
11129
|
+
description: "Request management for Jellyfin",
|
|
11130
|
+
category: "request",
|
|
11131
|
+
defaultPort: 5055,
|
|
11132
|
+
image: "fallenbagel/jellyseerr:latest",
|
|
11133
|
+
puid: 13012,
|
|
11134
|
+
pgid: 13000,
|
|
11135
|
+
volumes: (root) => [`${root}/config/jellyseerr:/app/config`],
|
|
11136
|
+
dependsOn: ["jellyfin"],
|
|
11137
|
+
apiKeyMeta: {
|
|
11138
|
+
configFile: "settings.json",
|
|
11139
|
+
parser: "json",
|
|
11140
|
+
selector: "main.apiKey"
|
|
11141
|
+
},
|
|
11142
|
+
homepage: { icon: "jellyseerr.png", widget: "jellyseerr" },
|
|
11143
|
+
logVolume: "/app/config/logs"
|
|
11144
|
+
},
|
|
11145
|
+
homarr: {
|
|
11146
|
+
id: "homarr",
|
|
11147
|
+
name: "Homarr",
|
|
11148
|
+
description: "Modern dashboard for all services",
|
|
11149
|
+
category: "dashboard",
|
|
11150
|
+
defaultPort: 7575,
|
|
11151
|
+
image: "ghcr.io/ajnart/homarr:latest",
|
|
11152
|
+
puid: 0,
|
|
11153
|
+
pgid: 0,
|
|
11154
|
+
volumes: (root) => [
|
|
11155
|
+
`${root}/config/homarr/configs:/app/data/configs`,
|
|
11156
|
+
`${root}/config/homarr/icons:/app/public/icons`,
|
|
11157
|
+
`${root}/config/homarr/data:/data`,
|
|
11158
|
+
"/var/run/docker.sock:/var/run/docker.sock"
|
|
11159
|
+
],
|
|
11160
|
+
homepage: { icon: "homarr.png" },
|
|
11161
|
+
logVolume: "/app/data/logs"
|
|
11162
|
+
},
|
|
11163
|
+
heimdall: {
|
|
11164
|
+
id: "heimdall",
|
|
11165
|
+
name: "Heimdall",
|
|
11166
|
+
description: "Application dashboard and launcher",
|
|
11167
|
+
category: "dashboard",
|
|
11168
|
+
defaultPort: 8082,
|
|
11169
|
+
image: "lscr.io/linuxserver/heimdall:latest",
|
|
11170
|
+
puid: 0,
|
|
11171
|
+
pgid: 13000,
|
|
11172
|
+
volumes: (root) => [`${root}/config/heimdall:/config`],
|
|
11173
|
+
homepage: { icon: "heimdall.png" },
|
|
11174
|
+
logVolume: "/config/log"
|
|
11175
|
+
},
|
|
11176
|
+
homepage: {
|
|
11177
|
+
id: "homepage",
|
|
11178
|
+
name: "Homepage",
|
|
11179
|
+
description: "Highly customizable application dashboard",
|
|
11180
|
+
category: "dashboard",
|
|
11181
|
+
defaultPort: 3009,
|
|
11182
|
+
internalPort: 3000,
|
|
11183
|
+
image: "ghcr.io/gethomepage/homepage:latest",
|
|
11184
|
+
puid: 0,
|
|
11185
|
+
pgid: 0,
|
|
11186
|
+
volumes: (root) => [
|
|
11187
|
+
`${root}/config/homepage:/app/config`,
|
|
11188
|
+
"/var/run/docker.sock:/var/run/docker.sock"
|
|
11189
|
+
],
|
|
11190
|
+
environment: {
|
|
11191
|
+
HOMEPAGE_ALLOWED_HOSTS: "homepage,homepage.${CLOUDFLARE_DNS_ZONE},${CLOUDFLARE_DNS_ZONE},localhost,${LOCAL_DOCKER_IP},${LOCAL_DOCKER_IP}:3009"
|
|
11192
|
+
},
|
|
11193
|
+
logVolume: "/app/config/logs"
|
|
11194
|
+
},
|
|
11195
|
+
portainer: {
|
|
11196
|
+
id: "portainer",
|
|
11197
|
+
name: "Portainer",
|
|
11198
|
+
description: "Docker container management UI",
|
|
11199
|
+
category: "utility",
|
|
11200
|
+
defaultPort: 9000,
|
|
11201
|
+
image: "portainer/portainer-ce:latest",
|
|
11202
|
+
puid: 0,
|
|
11203
|
+
pgid: 0,
|
|
11204
|
+
volumes: (root) => [
|
|
11205
|
+
`${root}/config/portainer:/data`,
|
|
11206
|
+
"/var/run/docker.sock:/var/run/docker.sock"
|
|
11207
|
+
],
|
|
11208
|
+
minPasswordLength: 12,
|
|
11209
|
+
homepage: { icon: "portainer.png", widget: "portainer" },
|
|
11210
|
+
logVolume: "/data/logs"
|
|
11211
|
+
},
|
|
11212
|
+
huntarr: {
|
|
11213
|
+
id: "huntarr",
|
|
11214
|
+
name: "Huntarr",
|
|
11215
|
+
description: "Missing content manager for *arr apps",
|
|
11216
|
+
category: "utility",
|
|
11217
|
+
defaultPort: 9705,
|
|
11218
|
+
image: "huntarr/huntarr:latest",
|
|
11219
|
+
puid: 0,
|
|
11220
|
+
pgid: 13000,
|
|
11221
|
+
volumes: (root) => [`${root}/config/huntarr:/config`],
|
|
11222
|
+
dependsOn: ["sonarr", "radarr", "lidarr", "readarr"],
|
|
11223
|
+
homepage: {
|
|
11224
|
+
icon: "huntarr.png",
|
|
11225
|
+
widget: "customapi",
|
|
11226
|
+
widgetFields: {
|
|
11227
|
+
url: "http://huntarr:9705/api/cycle/status",
|
|
11228
|
+
mappings: JSON.stringify([
|
|
11229
|
+
{ field: "sonarr.next_cycle", label: "Sonarr", format: "relativeDate" },
|
|
11230
|
+
{ field: "radarr.next_cycle", label: "Radarr", format: "relativeDate" },
|
|
11231
|
+
{ field: "lidarr.next_cycle", label: "Lidarr", format: "relativeDate" },
|
|
11232
|
+
{ field: "readarr.next_cycle", label: "Readarr", format: "relativeDate" },
|
|
11233
|
+
{ field: "whisparr.next_cycle", label: "Whisparr", format: "relativeDate" }
|
|
11234
|
+
])
|
|
11235
|
+
}
|
|
11236
|
+
},
|
|
11237
|
+
autoSetup: {
|
|
11238
|
+
type: "full",
|
|
11239
|
+
description: "Test connections to Sonarr, Radarr, Lidarr, Readarr, Whisparr",
|
|
11240
|
+
requires: ["sonarr", "radarr"]
|
|
11241
|
+
},
|
|
11242
|
+
logVolume: "/config/logs"
|
|
11243
|
+
},
|
|
11244
|
+
maintainerr: {
|
|
11245
|
+
id: "maintainerr",
|
|
11246
|
+
name: "Maintainerr",
|
|
11247
|
+
description: "Automated media management and cleanup for Plex",
|
|
11248
|
+
category: "utility",
|
|
11249
|
+
defaultPort: 6246,
|
|
11250
|
+
image: "ghcr.io/maintainerr/maintainerr:latest",
|
|
11251
|
+
puid: 0,
|
|
11252
|
+
pgid: 13000,
|
|
11253
|
+
volumes: (root) => [`${root}/config/maintainerr:/opt/data`],
|
|
11254
|
+
dependsOn: ["plex"],
|
|
11255
|
+
homepage: {
|
|
11256
|
+
icon: "maintainerr.png",
|
|
11257
|
+
widget: "customapi",
|
|
11258
|
+
widgetFields: {
|
|
11259
|
+
url: "http://maintainerr:6246/api/settings/version",
|
|
11260
|
+
mappings: JSON.stringify([{ field: "version", label: "Version" }])
|
|
11261
|
+
}
|
|
11262
|
+
},
|
|
11263
|
+
autoSetup: {
|
|
11264
|
+
type: "full",
|
|
11265
|
+
description: "Generate API key, configure Plex/Radarr/Sonarr/Overseerr/Tautulli connections",
|
|
11266
|
+
requires: ["plex"]
|
|
11267
|
+
},
|
|
11268
|
+
logVolume: "/opt/data/logs"
|
|
11269
|
+
},
|
|
11270
|
+
unpackerr: {
|
|
11271
|
+
id: "unpackerr",
|
|
11272
|
+
name: "Unpackerr",
|
|
11273
|
+
description: "Archive extraction for *arr apps",
|
|
11274
|
+
category: "utility",
|
|
11275
|
+
defaultPort: 5656,
|
|
11276
|
+
image: "golift/unpackerr",
|
|
11277
|
+
puid: 0,
|
|
11278
|
+
pgid: 13000,
|
|
11279
|
+
volumes: (root) => [`${root}/config/unpackerr:/config`, `${root}/data:/data`],
|
|
11280
|
+
logVolume: "/config/logs"
|
|
11281
|
+
},
|
|
11282
|
+
filebot: {
|
|
11283
|
+
id: "filebot",
|
|
11284
|
+
name: "FileBot",
|
|
11285
|
+
description: "Media file renaming and automator",
|
|
11286
|
+
category: "utility",
|
|
11287
|
+
defaultPort: 5452,
|
|
11288
|
+
image: "rednoah/filebot",
|
|
11289
|
+
puid: 13000,
|
|
11290
|
+
pgid: 13000,
|
|
11291
|
+
volumes: (root) => [`${root}/config/filebot:/data`, `${root}/data:/data`],
|
|
11292
|
+
environment: { DARK_MODE: "1" },
|
|
11293
|
+
logVolume: "/data/logs"
|
|
11294
|
+
},
|
|
11295
|
+
chromium: {
|
|
11296
|
+
id: "chromium",
|
|
11297
|
+
name: "Chromium",
|
|
11298
|
+
description: "Web browser for secure remote browsing",
|
|
11299
|
+
category: "utility",
|
|
11300
|
+
defaultPort: 3000,
|
|
11301
|
+
image: "lscr.io/linuxserver/chromium:latest",
|
|
11302
|
+
puid: 13000,
|
|
11303
|
+
pgid: 13000,
|
|
11304
|
+
volumes: (root) => [`${root}/config/chromium:/config`],
|
|
11305
|
+
environment: { TITLE: "Chromium" },
|
|
11306
|
+
logVolume: "/config/logs"
|
|
11307
|
+
},
|
|
11308
|
+
guacamole: {
|
|
11309
|
+
id: "guacamole",
|
|
11310
|
+
name: "Guacamole",
|
|
11311
|
+
description: "Clientless remote desktop gateway",
|
|
11312
|
+
category: "utility",
|
|
11313
|
+
defaultPort: 8080,
|
|
11314
|
+
image: "guacamole/guacamole",
|
|
11315
|
+
puid: 0,
|
|
11316
|
+
pgid: 0,
|
|
11317
|
+
volumes: (root) => [`${root}/config/guacamole:/config`],
|
|
11318
|
+
environment: {
|
|
11319
|
+
WEBAPP_CONTEXT: "ROOT",
|
|
11320
|
+
GUACD_HOSTNAME: "guacd",
|
|
11321
|
+
POSTGRESQL_HOSTNAME: "postgresql",
|
|
11322
|
+
POSTGRESQL_DATABASE: "guacamole",
|
|
11323
|
+
POSTGRESQL_USER: "${USERNAME_POSTGRESQL}",
|
|
11324
|
+
POSTGRESQL_PASSWORD: "${PASSWORD_POSTGRESQL}"
|
|
11325
|
+
},
|
|
11326
|
+
dependsOn: ["guacd", "postgresql"],
|
|
11327
|
+
secrets: [
|
|
11328
|
+
{
|
|
11329
|
+
name: "USERNAME_POSTGRESQL",
|
|
11330
|
+
description: "PostgreSQL Username",
|
|
11331
|
+
required: true,
|
|
11332
|
+
default: "postgres"
|
|
11333
|
+
},
|
|
11334
|
+
{
|
|
11335
|
+
name: "PASSWORD_POSTGRESQL",
|
|
11336
|
+
description: "PostgreSQL Password",
|
|
11337
|
+
required: true,
|
|
11338
|
+
mask: true
|
|
11339
|
+
}
|
|
11340
|
+
],
|
|
11341
|
+
logVolume: "/guacamole/logs"
|
|
11342
|
+
},
|
|
11343
|
+
guacd: {
|
|
11344
|
+
id: "guacd",
|
|
11345
|
+
name: "Guacd",
|
|
11346
|
+
description: "Guacamole proxy daemon",
|
|
11347
|
+
category: "utility",
|
|
11348
|
+
defaultPort: 4822,
|
|
11349
|
+
image: "guacamole/guacd",
|
|
11350
|
+
puid: 0,
|
|
11351
|
+
pgid: 13000,
|
|
11352
|
+
volumes: (root) => [`${root}/config/guacd:/config`],
|
|
11353
|
+
dependsOn: ["postgresql"],
|
|
11354
|
+
logVolume: "/guacd/logs"
|
|
11355
|
+
},
|
|
11356
|
+
"ddns-updater": {
|
|
11357
|
+
id: "ddns-updater",
|
|
11358
|
+
name: "DDNS-Updater",
|
|
11359
|
+
description: "Dynamic DNS record updater",
|
|
11360
|
+
category: "utility",
|
|
11361
|
+
defaultPort: 8000,
|
|
11362
|
+
image: "qmcgaw/ddns-updater",
|
|
11363
|
+
puid: 13000,
|
|
11364
|
+
pgid: 13000,
|
|
11365
|
+
volumes: (root) => [`${root}/config/ddns-updater:/data`],
|
|
11366
|
+
logVolume: "/data/logs"
|
|
11367
|
+
},
|
|
11368
|
+
easiarr: {
|
|
11369
|
+
id: "easiarr",
|
|
11370
|
+
name: "easiarr",
|
|
11371
|
+
description: "Exposes easiarr config and bookmarks for Homepage dashboard",
|
|
11372
|
+
category: "utility",
|
|
11373
|
+
defaultPort: 3010,
|
|
11374
|
+
internalPort: 8080,
|
|
11375
|
+
image: "halverneus/static-file-server:latest",
|
|
11376
|
+
puid: 0,
|
|
11377
|
+
pgid: 0,
|
|
11378
|
+
volumes: () => [
|
|
11379
|
+
"${XDG_CONFIG_HOME}/easiarr/config.json:/web/config.json:ro",
|
|
11380
|
+
"${XDG_CONFIG_HOME}/easiarr/bookmarks-local.html:/web/bookmarks-local.html:ro",
|
|
11381
|
+
"${XDG_CONFIG_HOME}/easiarr/bookmarks-remote.html:/web/bookmarks-remote.html:ro"
|
|
11382
|
+
],
|
|
11383
|
+
environment: {
|
|
11384
|
+
FOLDER: "/web",
|
|
11385
|
+
CORS: "true"
|
|
11386
|
+
},
|
|
11387
|
+
homepage: {
|
|
11388
|
+
icon: "mdi-docker",
|
|
11389
|
+
widget: "customapi",
|
|
11390
|
+
widgetFields: {
|
|
11391
|
+
url: "http://easiarr:8080/config.json",
|
|
11392
|
+
mappings: JSON.stringify([
|
|
11393
|
+
{ field: "version", label: "Version" },
|
|
11394
|
+
{ field: "apps.length", label: "Apps" }
|
|
11395
|
+
])
|
|
11396
|
+
}
|
|
11397
|
+
}
|
|
11398
|
+
},
|
|
11399
|
+
recyclarr: {
|
|
11400
|
+
id: "recyclarr",
|
|
11401
|
+
name: "Recyclarr",
|
|
11402
|
+
description: "Automatic TRaSH Guides profile sync for *arr apps",
|
|
11403
|
+
category: "utility",
|
|
11404
|
+
defaultPort: 0,
|
|
11405
|
+
image: "ghcr.io/recyclarr/recyclarr:latest",
|
|
11406
|
+
puid: 0,
|
|
11407
|
+
pgid: 0,
|
|
11408
|
+
useDockerUser: true,
|
|
11409
|
+
volumes: (root) => [`${root}/config/recyclarr:/config`],
|
|
11410
|
+
environment: {
|
|
11411
|
+
RECYCLARR_CREATE_CONFIG: "false",
|
|
11412
|
+
CRON_SCHEDULE: "@daily"
|
|
11413
|
+
},
|
|
11414
|
+
dependsOn: ["radarr", "sonarr"],
|
|
11415
|
+
autoSetup: {
|
|
11416
|
+
type: "full",
|
|
11417
|
+
description: "Generate recyclarr.yml config for enabled *arr apps with TRaSH profiles",
|
|
11418
|
+
requires: ["radarr", "sonarr"]
|
|
11419
|
+
}
|
|
11420
|
+
},
|
|
11421
|
+
profilarr: {
|
|
11422
|
+
id: "profilarr",
|
|
11423
|
+
name: "Profilarr",
|
|
11424
|
+
description: "Web UI for managing TRaSH Guides profiles (alternative to Recyclarr)",
|
|
11425
|
+
category: "utility",
|
|
11426
|
+
defaultPort: 6868,
|
|
11427
|
+
image: "santiagosayshey/profilarr:latest",
|
|
11428
|
+
puid: 1000,
|
|
11429
|
+
pgid: 1000,
|
|
11430
|
+
volumes: (root) => [`${root}/config/profilarr:/config`],
|
|
11431
|
+
dependsOn: ["radarr", "sonarr"],
|
|
11432
|
+
homepage: {
|
|
11433
|
+
icon: "profilarr"
|
|
11434
|
+
}
|
|
11435
|
+
},
|
|
11436
|
+
gluetun: {
|
|
11437
|
+
id: "gluetun",
|
|
11438
|
+
name: "Gluetun",
|
|
11439
|
+
description: "VPN client container for routing traffic",
|
|
11440
|
+
category: "vpn",
|
|
11441
|
+
defaultPort: 8888,
|
|
11442
|
+
image: "qmcgaw/gluetun:latest",
|
|
11443
|
+
puid: 0,
|
|
11444
|
+
pgid: 0,
|
|
11445
|
+
cap_add: ["NET_ADMIN"],
|
|
11446
|
+
devices: ["/dev/net/tun:/dev/net/tun"],
|
|
11447
|
+
volumes: (root) => [`${root}/config/gluetun:/gluetun`],
|
|
11448
|
+
environment: {
|
|
11449
|
+
VPN_SERVICE_PROVIDER: "${VPN_SERVICE_PROVIDER}",
|
|
11450
|
+
OPENVPN_USER: "${USERNAME_VPN}",
|
|
11451
|
+
OPENVPN_PASSWORD: "${PASSWORD_VPN}",
|
|
11452
|
+
WIREGUARD_PRIVATE_KEY: "${WIREGUARD_PRIVATE_KEY}",
|
|
11453
|
+
HTTPPROXY: "on",
|
|
11454
|
+
SHADOWSOCKS: "on"
|
|
11455
|
+
},
|
|
11456
|
+
secrets: [
|
|
11457
|
+
{
|
|
11458
|
+
name: "VPN_SERVICE_PROVIDER",
|
|
11459
|
+
description: "VPN Provider (e.g. custom, airvpn)",
|
|
11460
|
+
required: true,
|
|
11461
|
+
default: "custom"
|
|
11462
|
+
},
|
|
11463
|
+
{
|
|
11464
|
+
name: "USERNAME_VPN",
|
|
11465
|
+
description: "OpenVPN Username",
|
|
11466
|
+
required: false
|
|
11467
|
+
},
|
|
11468
|
+
{
|
|
11469
|
+
name: "PASSWORD_VPN",
|
|
11470
|
+
description: "OpenVPN Password",
|
|
11471
|
+
required: false,
|
|
11472
|
+
mask: true
|
|
11473
|
+
},
|
|
11474
|
+
{
|
|
11475
|
+
name: "WIREGUARD_PRIVATE_KEY",
|
|
11476
|
+
description: "WireGuard Private Key",
|
|
11477
|
+
required: false,
|
|
11478
|
+
mask: true
|
|
11479
|
+
}
|
|
11480
|
+
],
|
|
11481
|
+
homepage: { icon: "gluetun.png", widget: "gluetun" },
|
|
11482
|
+
logVolume: "/gluetun"
|
|
11483
|
+
},
|
|
11484
|
+
grafana: {
|
|
11485
|
+
id: "grafana",
|
|
11486
|
+
name: "Grafana",
|
|
11487
|
+
description: "Visual monitoring dashboard",
|
|
11488
|
+
category: "monitoring",
|
|
11489
|
+
defaultPort: 3001,
|
|
11490
|
+
image: "grafana/grafana-enterprise",
|
|
11491
|
+
puid: 0,
|
|
11492
|
+
pgid: 13000,
|
|
11493
|
+
volumes: (root) => [`${root}/config/grafana:/var/lib/grafana`],
|
|
11494
|
+
homepage: { icon: "grafana.png", widget: "grafana" },
|
|
11495
|
+
autoSetup: {
|
|
11496
|
+
type: "full",
|
|
11497
|
+
description: "Setup admin user, configure Prometheus datasource",
|
|
11498
|
+
requires: ["prometheus"]
|
|
11499
|
+
},
|
|
11500
|
+
logVolume: "/var/log/grafana"
|
|
11501
|
+
},
|
|
11502
|
+
prometheus: {
|
|
11503
|
+
id: "prometheus",
|
|
11504
|
+
name: "Prometheus",
|
|
11505
|
+
description: "Systems and service monitoring",
|
|
11506
|
+
category: "monitoring",
|
|
11507
|
+
defaultPort: 9090,
|
|
11508
|
+
image: "prom/prometheus",
|
|
11509
|
+
puid: 0,
|
|
11510
|
+
pgid: 13000,
|
|
11511
|
+
volumes: (root) => [`${root}/config/prometheus:/prometheus`],
|
|
11512
|
+
homepage: { icon: "prometheus.png", widget: "prometheus" },
|
|
11513
|
+
logVolume: "/prometheus/logs"
|
|
11514
|
+
},
|
|
11515
|
+
dozzle: {
|
|
11516
|
+
id: "dozzle",
|
|
11517
|
+
name: "Dozzle",
|
|
11518
|
+
description: "Real-time log viewer for Docker containers",
|
|
11519
|
+
category: "monitoring",
|
|
11520
|
+
defaultPort: 8080,
|
|
11521
|
+
image: "amir20/dozzle",
|
|
11522
|
+
puid: 0,
|
|
11523
|
+
pgid: 0,
|
|
11524
|
+
volumes: () => ["/var/run/docker.sock:/var/run/docker.sock"]
|
|
11525
|
+
},
|
|
11526
|
+
"uptime-kuma": {
|
|
11527
|
+
id: "uptime-kuma",
|
|
11528
|
+
name: "Uptime Kuma",
|
|
11529
|
+
description: "Self-hosted monitoring tool",
|
|
11530
|
+
category: "monitoring",
|
|
11531
|
+
defaultPort: 3001,
|
|
11532
|
+
image: "louislam/uptime-kuma:1",
|
|
11533
|
+
puid: 0,
|
|
11534
|
+
pgid: 0,
|
|
11535
|
+
volumes: (root) => [
|
|
11536
|
+
`${root}/config/uptime-kuma:/app/data`,
|
|
11537
|
+
"/var/run/docker.sock:/var/run/docker.sock"
|
|
11538
|
+
],
|
|
11539
|
+
homepage: { icon: "uptime-kuma.png", widget: "uptimekuma" },
|
|
11540
|
+
autoSetup: {
|
|
11541
|
+
type: "full",
|
|
11542
|
+
description: "Create admin user, add monitors for enabled apps"
|
|
11543
|
+
},
|
|
11544
|
+
logVolume: "/app/data/logs"
|
|
11545
|
+
},
|
|
11546
|
+
traefik: {
|
|
11547
|
+
id: "traefik",
|
|
11548
|
+
name: "Traefik",
|
|
11549
|
+
description: "Reverse proxy and load balancer",
|
|
11550
|
+
category: "infrastructure",
|
|
11551
|
+
defaultPort: 80,
|
|
11552
|
+
internalPort: 80,
|
|
11553
|
+
image: "traefik:latest",
|
|
11554
|
+
puid: 0,
|
|
11555
|
+
pgid: 0,
|
|
11556
|
+
volumes: (root) => [
|
|
11557
|
+
`${root}/config/traefik:/etc/traefik`,
|
|
11558
|
+
`${root}/config/traefik/letsencrypt:/letsencrypt`,
|
|
11559
|
+
"/var/run/docker.sock:/var/run/docker.sock:ro"
|
|
11560
|
+
],
|
|
11561
|
+
secondaryPorts: ["8083:8080"],
|
|
11562
|
+
secrets: [
|
|
11563
|
+
{
|
|
11564
|
+
name: "CLOUDFLARE_DNS_ZONE",
|
|
11565
|
+
description: "Root Domain (e.g. example.com)",
|
|
11566
|
+
required: true
|
|
11567
|
+
}
|
|
11568
|
+
],
|
|
11569
|
+
homepage: { icon: "traefik.png", widget: "traefik" },
|
|
11570
|
+
logVolume: "/etc/traefik/logs"
|
|
11571
|
+
},
|
|
11572
|
+
caddy: {
|
|
11573
|
+
id: "caddy",
|
|
11574
|
+
name: "Caddy",
|
|
11575
|
+
description: "Web server with automatic HTTPS and reverse proxy",
|
|
11576
|
+
category: "infrastructure",
|
|
11577
|
+
defaultPort: 80,
|
|
11578
|
+
internalPort: 80,
|
|
11579
|
+
secondaryPorts: ["443:443"],
|
|
11580
|
+
image: "caddy:latest",
|
|
11581
|
+
puid: 0,
|
|
11582
|
+
pgid: 0,
|
|
11583
|
+
volumes: (root) => [
|
|
11584
|
+
`${root}/config/caddy/Caddyfile:/etc/caddy/Caddyfile`,
|
|
11585
|
+
`${root}/config/caddy/data:/data`,
|
|
11586
|
+
`${root}/config/caddy/config:/config`
|
|
11587
|
+
],
|
|
11588
|
+
homepage: { icon: "caddy.png" },
|
|
11589
|
+
logVolume: "/data/logs"
|
|
11590
|
+
},
|
|
11591
|
+
cloudflared: {
|
|
11592
|
+
id: "cloudflared",
|
|
11593
|
+
name: "Cloudflared",
|
|
11594
|
+
description: "Cloudflare Tunnel for secure external access without port forwarding",
|
|
11595
|
+
category: "infrastructure",
|
|
11596
|
+
defaultPort: 0,
|
|
11597
|
+
image: "cloudflare/cloudflared:latest",
|
|
11598
|
+
puid: 0,
|
|
11599
|
+
pgid: 0,
|
|
11600
|
+
volumes: () => [],
|
|
11601
|
+
environment: {
|
|
11602
|
+
TUNNEL_TOKEN: "${CLOUDFLARE_TUNNEL_TOKEN}"
|
|
11603
|
+
},
|
|
11604
|
+
command: "tunnel run",
|
|
11605
|
+
dependsOn: ["traefik"],
|
|
11606
|
+
secrets: [
|
|
11607
|
+
{
|
|
11608
|
+
name: "CLOUDFLARE_API_TOKEN",
|
|
11609
|
+
description: "Cloudflare API Token (for automated tunnel setup via Menu)",
|
|
11610
|
+
required: false,
|
|
11611
|
+
mask: true
|
|
11612
|
+
},
|
|
11613
|
+
{
|
|
11614
|
+
name: "CLOUDFLARE_TUNNEL_TOKEN",
|
|
11615
|
+
description: "Cloudflare Tunnel Token (auto-generated or from Zero Trust)",
|
|
11616
|
+
required: true,
|
|
11617
|
+
mask: true
|
|
11618
|
+
}
|
|
11619
|
+
],
|
|
11620
|
+
homepage: { icon: "cloudflare-zero-trust.png", widget: "cloudflared" }
|
|
11621
|
+
},
|
|
11622
|
+
"traefik-certs-dumper": {
|
|
11623
|
+
id: "traefik-certs-dumper",
|
|
11624
|
+
name: "Traefik Certs Dumper",
|
|
11625
|
+
description: "Extracts certificates from Traefik",
|
|
11626
|
+
category: "infrastructure",
|
|
11627
|
+
defaultPort: 0,
|
|
11628
|
+
image: "ldez/traefik-certs-dumper:latest",
|
|
11629
|
+
puid: 0,
|
|
11630
|
+
pgid: 0,
|
|
11631
|
+
volumes: (root) => [
|
|
11632
|
+
`${root}/config/traefik/letsencrypt:/traefik:ro`,
|
|
11633
|
+
`${root}/config/traefik/certs:/output`
|
|
11634
|
+
],
|
|
11635
|
+
dependsOn: ["traefik"]
|
|
11636
|
+
},
|
|
11637
|
+
crowdsec: {
|
|
11638
|
+
id: "crowdsec",
|
|
11639
|
+
name: "CrowdSec",
|
|
11640
|
+
description: "Intrusion prevention system",
|
|
11641
|
+
category: "infrastructure",
|
|
11642
|
+
defaultPort: 8080,
|
|
11643
|
+
image: "crowdsecurity/crowdsec:latest",
|
|
11644
|
+
puid: 0,
|
|
11645
|
+
pgid: 0,
|
|
11646
|
+
volumes: (root) => [
|
|
11647
|
+
`${root}/config/crowdsec:/etc/crowdsec`,
|
|
11648
|
+
"/var/run/docker.sock:/var/run/docker.sock:ro"
|
|
11649
|
+
],
|
|
11650
|
+
homepage: { icon: "crowdsec.png", widget: "crowdsec" }
|
|
11651
|
+
},
|
|
11652
|
+
headscale: {
|
|
11653
|
+
id: "headscale",
|
|
11654
|
+
name: "Headscale",
|
|
11655
|
+
description: "Open-source Tailscale control server",
|
|
11656
|
+
category: "infrastructure",
|
|
11657
|
+
defaultPort: 8084,
|
|
11658
|
+
image: "headscale/headscale:latest",
|
|
11659
|
+
puid: 0,
|
|
11660
|
+
pgid: 0,
|
|
11661
|
+
volumes: (root) => [
|
|
11662
|
+
`${root}/config/headscale:/etc/headscale`,
|
|
11663
|
+
`${root}/config/headscale/data:/var/lib/headscale`
|
|
11664
|
+
],
|
|
11665
|
+
homepage: { icon: "headscale.png", widget: "headscale" }
|
|
11666
|
+
},
|
|
11667
|
+
headplane: {
|
|
11668
|
+
id: "headplane",
|
|
11669
|
+
name: "Headplane",
|
|
11670
|
+
description: "Headscale web UI",
|
|
11671
|
+
category: "infrastructure",
|
|
11672
|
+
defaultPort: 3000,
|
|
11673
|
+
image: "ghcr.io/tale/headplane:latest",
|
|
11674
|
+
puid: 0,
|
|
11675
|
+
pgid: 0,
|
|
11676
|
+
volumes: (root) => [`${root}/config/headplane:/config`],
|
|
11677
|
+
dependsOn: ["headscale"]
|
|
11678
|
+
},
|
|
11679
|
+
tailscale: {
|
|
11680
|
+
id: "tailscale",
|
|
11681
|
+
name: "Tailscale",
|
|
11682
|
+
description: "VPN mesh network client",
|
|
11683
|
+
category: "infrastructure",
|
|
11684
|
+
defaultPort: 0,
|
|
11685
|
+
image: "tailscale/tailscale:latest",
|
|
11686
|
+
puid: 0,
|
|
11687
|
+
pgid: 0,
|
|
11688
|
+
cap_add: ["NET_ADMIN"],
|
|
11689
|
+
devices: ["/dev/net/tun:/dev/net/tun"],
|
|
11690
|
+
volumes: (root) => [`${root}/config/tailscale:/var/lib/tailscale`],
|
|
11691
|
+
secrets: [
|
|
11692
|
+
{
|
|
11693
|
+
name: "TAILSCALE_AUTHKEY",
|
|
11694
|
+
description: "Tailscale Auth Key",
|
|
11695
|
+
required: true,
|
|
11696
|
+
mask: true
|
|
11697
|
+
}
|
|
11698
|
+
],
|
|
11699
|
+
homepage: { icon: "tailscale.png", widget: "tailscale" }
|
|
11700
|
+
},
|
|
11701
|
+
authentik: {
|
|
11702
|
+
id: "authentik",
|
|
11703
|
+
name: "Authentik",
|
|
11704
|
+
description: "Identity provider and SSO (Server)",
|
|
11705
|
+
category: "infrastructure",
|
|
11706
|
+
defaultPort: 9001,
|
|
11707
|
+
image: "ghcr.io/goauthentik/server:latest",
|
|
11708
|
+
puid: 0,
|
|
11709
|
+
pgid: 13000,
|
|
11710
|
+
volumes: (root) => [
|
|
11711
|
+
`${root}/config/authentik/media:/media`,
|
|
11712
|
+
`${root}/config/authentik/templates:/templates`
|
|
11713
|
+
],
|
|
11714
|
+
environment: {
|
|
11715
|
+
AUTHENTIK_REDIS__HOST: "valkey",
|
|
11716
|
+
AUTHENTIK_POSTGRESQL__HOST: "postgresql",
|
|
11717
|
+
AUTHENTIK_POSTGRESQL__NAME: "authentik",
|
|
11718
|
+
AUTHENTIK_POSTGRESQL__USER: "${USERNAME_POSTGRESQL}",
|
|
11719
|
+
AUTHENTIK_POSTGRESQL__PASSWORD: "${PASSWORD_POSTGRESQL}",
|
|
11720
|
+
AUTHENTIK_SECRET_KEY: "${AUTHENTIK_SECRET_KEY}"
|
|
11721
|
+
},
|
|
11722
|
+
dependsOn: ["postgresql", "valkey", "authentik-worker"],
|
|
11723
|
+
secrets: [
|
|
11724
|
+
{
|
|
11725
|
+
name: "AUTHENTIK_SECRET_KEY",
|
|
11726
|
+
description: "Authentik Secret Key",
|
|
11727
|
+
required: true,
|
|
11728
|
+
mask: true,
|
|
11729
|
+
generate: true
|
|
11730
|
+
},
|
|
11731
|
+
{
|
|
11732
|
+
name: "USERNAME_POSTGRESQL",
|
|
11733
|
+
description: "Postgres Username",
|
|
11734
|
+
required: true,
|
|
11735
|
+
default: "postgres"
|
|
11736
|
+
},
|
|
11737
|
+
{
|
|
11738
|
+
name: "PASSWORD_POSTGRESQL",
|
|
11739
|
+
description: "Postgres Password",
|
|
11740
|
+
required: true,
|
|
11741
|
+
mask: true
|
|
11742
|
+
}
|
|
11743
|
+
],
|
|
11744
|
+
homepage: { icon: "authentik.png", widget: "authentik" }
|
|
11745
|
+
},
|
|
11746
|
+
"authentik-worker": {
|
|
11747
|
+
id: "authentik-worker",
|
|
11748
|
+
name: "Authentik Worker",
|
|
11749
|
+
description: "Identity provider background worker",
|
|
11750
|
+
category: "infrastructure",
|
|
11751
|
+
defaultPort: 0,
|
|
11752
|
+
image: "ghcr.io/goauthentik/server:latest",
|
|
11753
|
+
puid: 0,
|
|
11754
|
+
pgid: 13000,
|
|
11755
|
+
volumes: (root) => [
|
|
11756
|
+
`${root}/config/authentik/media:/media`,
|
|
11757
|
+
`${root}/config/authentik/templates:/templates`,
|
|
11758
|
+
`${root}/config/authentik/certs:/certs`,
|
|
11759
|
+
"/var/run/docker.sock:/var/run/docker.sock"
|
|
11760
|
+
],
|
|
11761
|
+
environment: {
|
|
11762
|
+
AUTHENTIK_REDIS__HOST: "valkey",
|
|
11763
|
+
AUTHENTIK_POSTGRESQL__HOST: "postgresql",
|
|
11764
|
+
AUTHENTIK_POSTGRESQL__NAME: "authentik",
|
|
11765
|
+
AUTHENTIK_POSTGRESQL__USER: "${USERNAME_POSTGRESQL}",
|
|
11766
|
+
AUTHENTIK_POSTGRESQL__PASSWORD: "${PASSWORD_POSTGRESQL}",
|
|
11767
|
+
AUTHENTIK_SECRET_KEY: "${AUTHENTIK_SECRET_KEY}"
|
|
11768
|
+
},
|
|
11769
|
+
dependsOn: ["postgresql", "valkey"]
|
|
11770
|
+
},
|
|
11771
|
+
postgresql: {
|
|
11772
|
+
id: "postgresql",
|
|
11773
|
+
name: "PostgreSQL",
|
|
11774
|
+
description: "Database server",
|
|
11775
|
+
category: "infrastructure",
|
|
11776
|
+
defaultPort: 5432,
|
|
11777
|
+
image: "docker.io/library/postgres:latest",
|
|
11778
|
+
puid: 0,
|
|
11779
|
+
pgid: 13000,
|
|
11780
|
+
volumes: (root) => [`${root}/config/postgresql:/var/lib/postgresql/data`],
|
|
11781
|
+
environment: {
|
|
11782
|
+
POSTGRES_USER: "${USERNAME_POSTGRESQL}",
|
|
11783
|
+
POSTGRES_PASSWORD: "${PASSWORD_POSTGRESQL}",
|
|
11784
|
+
POSTGRES_DB: "authentik"
|
|
11785
|
+
},
|
|
11786
|
+
secrets: [
|
|
11787
|
+
{
|
|
11788
|
+
name: "USERNAME_POSTGRESQL",
|
|
11789
|
+
description: "PostgreSQL Username",
|
|
11790
|
+
required: true,
|
|
11791
|
+
default: "postgres"
|
|
11792
|
+
},
|
|
11793
|
+
{
|
|
11794
|
+
name: "PASSWORD_POSTGRESQL",
|
|
11795
|
+
description: "PostgreSQL Password",
|
|
11796
|
+
required: true,
|
|
11797
|
+
mask: true
|
|
11798
|
+
}
|
|
11799
|
+
]
|
|
11800
|
+
},
|
|
11801
|
+
valkey: {
|
|
11802
|
+
id: "valkey",
|
|
11803
|
+
name: "Valkey",
|
|
11804
|
+
description: "Redis-compatible key-value store",
|
|
11805
|
+
category: "infrastructure",
|
|
11806
|
+
defaultPort: 6379,
|
|
11807
|
+
image: "valkey/valkey:alpine",
|
|
11808
|
+
puid: 0,
|
|
11809
|
+
pgid: 13000,
|
|
11810
|
+
volumes: (root) => [`${root}/config/valkey:/data`]
|
|
11811
|
+
}
|
|
11812
|
+
};
|
|
11813
|
+
function getAppsByCategory() {
|
|
11814
|
+
const result = {};
|
|
11815
|
+
for (const app of Object.values(APPS)) {
|
|
11816
|
+
if (!result[app.category]) {
|
|
11817
|
+
result[app.category] = [];
|
|
11818
|
+
}
|
|
11819
|
+
result[app.category].push(app);
|
|
11820
|
+
}
|
|
11821
|
+
return result;
|
|
11822
|
+
}
|
|
11823
|
+
function getApp(id) {
|
|
11824
|
+
return APPS[id];
|
|
11825
|
+
}
|
|
11826
|
+
|
|
11897
11827
|
// src/config/homepage-config.ts
|
|
11898
|
-
init_registry();
|
|
11899
11828
|
init_env();
|
|
11900
11829
|
init_schema();
|
|
11901
11830
|
function getHomepageConfigPath(config) {
|
|
@@ -12317,7 +12246,6 @@ async function saveRecyclarrConfig(config) {
|
|
|
12317
12246
|
}
|
|
12318
12247
|
// src/config/bookmarks-generator.ts
|
|
12319
12248
|
import { writeFile as writeFile5 } from "fs/promises";
|
|
12320
|
-
init_registry();
|
|
12321
12249
|
init_env();
|
|
12322
12250
|
init_paths();
|
|
12323
12251
|
init_schema();
|
|
@@ -12674,7 +12602,7 @@ class AdvancedSettings {
|
|
|
12674
12602
|
}
|
|
12675
12603
|
const children = this.container.getChildren();
|
|
12676
12604
|
for (const child of children) {
|
|
12677
|
-
this.container.remove(child
|
|
12605
|
+
this.container.remove(child);
|
|
12678
12606
|
}
|
|
12679
12607
|
}
|
|
12680
12608
|
renderMenu() {
|
|
@@ -12783,7 +12711,6 @@ class AdvancedSettings {
|
|
|
12783
12711
|
}
|
|
12784
12712
|
|
|
12785
12713
|
// src/ui/screens/AppManager.ts
|
|
12786
|
-
init_registry();
|
|
12787
12714
|
import {
|
|
12788
12715
|
BoxRenderable as BoxRenderable7,
|
|
12789
12716
|
RGBA as RGBA3,
|
|
@@ -12793,18 +12720,16 @@ import {
|
|
|
12793
12720
|
} from "@opentui/core";
|
|
12794
12721
|
|
|
12795
12722
|
// src/compose/generator.ts
|
|
12796
|
-
|
|
12723
|
+
import { writeFile as writeFile9 } from "fs/promises";
|
|
12797
12724
|
init_manager();
|
|
12798
12725
|
init_debug();
|
|
12799
12726
|
init_env();
|
|
12800
|
-
import { writeFile as writeFile9 } from "fs/promises";
|
|
12801
12727
|
|
|
12802
12728
|
// src/compose/caddy-config.ts
|
|
12803
|
-
init_registry();
|
|
12804
|
-
init_debug();
|
|
12805
12729
|
import { existsSync as existsSync6 } from "fs";
|
|
12806
12730
|
import { mkdir as mkdir4, writeFile as writeFile7 } from "fs/promises";
|
|
12807
12731
|
import { join as join5 } from "path";
|
|
12732
|
+
init_debug();
|
|
12808
12733
|
function generateCaddyfile(config) {
|
|
12809
12734
|
const domain = config.caddy?.domain || "localhost";
|
|
12810
12735
|
const email = config.caddy?.email;
|
|
@@ -13219,7 +13144,6 @@ async function updateEnvFile(config) {
|
|
|
13219
13144
|
});
|
|
13220
13145
|
}
|
|
13221
13146
|
// src/structure/manager.ts
|
|
13222
|
-
init_registry();
|
|
13223
13147
|
import { mkdir as mkdir6 } from "fs/promises";
|
|
13224
13148
|
import { join as join7 } from "path";
|
|
13225
13149
|
var BASE_DIRS = ["torrents", "usenet", "media"];
|
|
@@ -13317,11 +13241,6 @@ import {
|
|
|
13317
13241
|
TabSelectRenderable,
|
|
13318
13242
|
TextRenderable as TextRenderable4
|
|
13319
13243
|
} from "@opentui/core";
|
|
13320
|
-
|
|
13321
|
-
// src/apps/index.ts
|
|
13322
|
-
init_registry();
|
|
13323
|
-
|
|
13324
|
-
// src/ui/components/ApplicationSelector.ts
|
|
13325
13244
|
class ApplicationSelector extends BoxRenderable5 {
|
|
13326
13245
|
selectedApps;
|
|
13327
13246
|
onToggle;
|
|
@@ -13417,7 +13336,7 @@ class ApplicationSelector extends BoxRenderable5 {
|
|
|
13417
13336
|
}
|
|
13418
13337
|
updateWarnings() {
|
|
13419
13338
|
const children = this.warningBox.getChildren();
|
|
13420
|
-
children.forEach((c) => this.warningBox.remove(c
|
|
13339
|
+
children.forEach((c) => this.warningBox.remove(c));
|
|
13421
13340
|
const warnings = this.getConflictWarnings();
|
|
13422
13341
|
warnings.forEach((w, i) => {
|
|
13423
13342
|
this.warningBox.add(new TextRenderable4(this._renderer, {
|
|
@@ -13513,8 +13432,6 @@ class ApplicationSelector extends BoxRenderable5 {
|
|
|
13513
13432
|
}
|
|
13514
13433
|
|
|
13515
13434
|
// src/ui/screens/SecretsEditor.ts
|
|
13516
|
-
init_registry();
|
|
13517
|
-
init_env();
|
|
13518
13435
|
import { mkdir as mkdir7 } from "fs/promises";
|
|
13519
13436
|
import { dirname } from "path";
|
|
13520
13437
|
import {
|
|
@@ -13523,6 +13440,7 @@ import {
|
|
|
13523
13440
|
RGBA as RGBA2,
|
|
13524
13441
|
TextRenderable as TextRenderable5
|
|
13525
13442
|
} from "@opentui/core";
|
|
13443
|
+
init_env();
|
|
13526
13444
|
|
|
13527
13445
|
class SecretsEditor extends BoxRenderable6 {
|
|
13528
13446
|
inputs = new Map;
|
|
@@ -13695,7 +13613,7 @@ class AppManager {
|
|
|
13695
13613
|
}
|
|
13696
13614
|
const children = this.container.getChildren();
|
|
13697
13615
|
for (const child of children) {
|
|
13698
|
-
this.container.remove(child
|
|
13616
|
+
this.container.remove(child);
|
|
13699
13617
|
}
|
|
13700
13618
|
const { container: page, content } = createPageLayout(this.renderer, {
|
|
13701
13619
|
title: "Manage Apps",
|
|
@@ -13850,7 +13768,7 @@ class AppManager {
|
|
|
13850
13768
|
]
|
|
13851
13769
|
});
|
|
13852
13770
|
menu.on(SelectRenderableEvents3.ITEM_SELECTED, (index) => {
|
|
13853
|
-
this.container.remove(
|
|
13771
|
+
this.container.remove(overlay);
|
|
13854
13772
|
if (index === 0) {
|
|
13855
13773
|
const editor = new SecretsEditor(this.renderer, {
|
|
13856
13774
|
id: "secrets-editor-overlay",
|
|
@@ -13858,11 +13776,11 @@ class AppManager {
|
|
|
13858
13776
|
height: "100%",
|
|
13859
13777
|
config: this.config,
|
|
13860
13778
|
onSave: () => {
|
|
13861
|
-
this.container.remove(
|
|
13779
|
+
this.container.remove(editor);
|
|
13862
13780
|
this.app.navigateTo("main");
|
|
13863
13781
|
},
|
|
13864
13782
|
onCancel: () => {
|
|
13865
|
-
this.container.remove(
|
|
13783
|
+
this.container.remove(editor);
|
|
13866
13784
|
this.app.navigateTo("main");
|
|
13867
13785
|
}
|
|
13868
13786
|
});
|
|
@@ -14144,8 +14062,7 @@ class ContainerControl {
|
|
|
14144
14062
|
clearPanel(panel) {
|
|
14145
14063
|
const children = [...panel.getChildren()];
|
|
14146
14064
|
for (const child of children) {
|
|
14147
|
-
|
|
14148
|
-
panel.remove(child.id);
|
|
14065
|
+
panel.remove(child);
|
|
14149
14066
|
}
|
|
14150
14067
|
}
|
|
14151
14068
|
updatePanels() {
|
|
@@ -14483,7 +14400,6 @@ import { randomBytes } from "crypto";
|
|
|
14483
14400
|
import { existsSync as existsSync8, readFileSync as readFileSync2, writeFileSync as writeFileSync3 } from "fs";
|
|
14484
14401
|
import { join as join8 } from "path";
|
|
14485
14402
|
import { BoxRenderable as BoxRenderable9, TextRenderable as TextRenderable8 } from "@opentui/core";
|
|
14486
|
-
init_registry();
|
|
14487
14403
|
init_env();
|
|
14488
14404
|
function generateApiKey() {
|
|
14489
14405
|
return randomBytes(16).toString("hex");
|
|
@@ -14778,11 +14694,9 @@ class ApiKeyViewer extends BoxRenderable9 {
|
|
|
14778
14694
|
destroy() {
|
|
14779
14695
|
this.cliRenderer.keyInput.off("keypress", this.keyHandler);
|
|
14780
14696
|
if (this.parent) {
|
|
14781
|
-
|
|
14782
|
-
|
|
14783
|
-
|
|
14784
|
-
} catch {}
|
|
14785
|
-
}
|
|
14697
|
+
try {
|
|
14698
|
+
this.parent.remove(this);
|
|
14699
|
+
} catch {}
|
|
14786
14700
|
}
|
|
14787
14701
|
}
|
|
14788
14702
|
async saveToEnv() {
|
|
@@ -15024,10 +14938,26 @@ class ArrApiClient {
|
|
|
15024
14938
|
return this.request("/rootfolder");
|
|
15025
14939
|
}
|
|
15026
14940
|
async addRootFolder(pathOrOptions) {
|
|
15027
|
-
const
|
|
14941
|
+
const options = typeof pathOrOptions === "string" ? { path: pathOrOptions } : { ...pathOrOptions };
|
|
14942
|
+
if (!options.name) {
|
|
14943
|
+
const folderName = options.path.split("/").filter(Boolean).pop() || "Media";
|
|
14944
|
+
options.name = folderName.charAt(0).toUpperCase() + folderName.slice(1);
|
|
14945
|
+
}
|
|
14946
|
+
if (!options.defaultQualityProfileId) {
|
|
14947
|
+
const qProfiles = await this.getQualityProfiles();
|
|
14948
|
+
if (qProfiles.length > 0) {
|
|
14949
|
+
options.defaultQualityProfileId = qProfiles[0].id;
|
|
14950
|
+
}
|
|
14951
|
+
}
|
|
14952
|
+
if (!options.defaultMetadataProfileId) {
|
|
14953
|
+
const mProfiles = await this.getMetadataProfiles();
|
|
14954
|
+
if (mProfiles.length > 0) {
|
|
14955
|
+
options.defaultMetadataProfileId = mProfiles[0].id;
|
|
14956
|
+
}
|
|
14957
|
+
}
|
|
15028
14958
|
return this.request("/rootfolder", {
|
|
15029
14959
|
method: "POST",
|
|
15030
|
-
body: JSON.stringify(
|
|
14960
|
+
body: JSON.stringify(options)
|
|
15031
14961
|
});
|
|
15032
14962
|
}
|
|
15033
14963
|
async getMetadataProfiles() {
|
|
@@ -15341,9 +15271,6 @@ class QBittorrentClient extends BaseApiClient {
|
|
|
15341
15271
|
}
|
|
15342
15272
|
}
|
|
15343
15273
|
|
|
15344
|
-
// src/ui/screens/AppConfigurator.ts
|
|
15345
|
-
init_registry();
|
|
15346
|
-
|
|
15347
15274
|
// src/ui/components/CredentialsForm.ts
|
|
15348
15275
|
import { BoxRenderable as BoxRenderable10, InputRenderable as InputRenderable2, TextRenderable as TextRenderable9 } from "@opentui/core";
|
|
15349
15276
|
|
|
@@ -15699,7 +15626,8 @@ class AppConfigurator extends BoxRenderable12 {
|
|
|
15699
15626
|
try {
|
|
15700
15627
|
const appConfig = this.config.apps.find((a) => a.id === appId);
|
|
15701
15628
|
const port = appConfig?.port ?? appDef.defaultPort;
|
|
15702
|
-
const
|
|
15629
|
+
const apiVersion = appDef.rootFolder?.apiVersion || "v3";
|
|
15630
|
+
const client = new ArrApiClient("localhost", port, apiKey, apiVersion);
|
|
15703
15631
|
const rootFolders = await client.getRootFolders();
|
|
15704
15632
|
const targetPath = appDef.rootFolder?.path;
|
|
15705
15633
|
const hasCorrectRoot = rootFolders.some((rf) => rf.path === targetPath);
|
|
@@ -15709,7 +15637,12 @@ class AppConfigurator extends BoxRenderable12 {
|
|
|
15709
15637
|
return;
|
|
15710
15638
|
}
|
|
15711
15639
|
if (!hasCorrectRoot && targetPath) {
|
|
15712
|
-
|
|
15640
|
+
const options = { path: targetPath };
|
|
15641
|
+
if (appId === "lidarr")
|
|
15642
|
+
options.name = "Music";
|
|
15643
|
+
if (appId === "readarr")
|
|
15644
|
+
options.name = "Books";
|
|
15645
|
+
await client.addRootFolder(options);
|
|
15713
15646
|
}
|
|
15714
15647
|
result.status = "success";
|
|
15715
15648
|
result.message = "Root folder set";
|
|
@@ -15741,11 +15674,9 @@ class AppConfigurator extends BoxRenderable12 {
|
|
|
15741
15674
|
updateDisplay() {
|
|
15742
15675
|
const contentChildren = [...this.contentBox.getChildren()];
|
|
15743
15676
|
for (const child of contentChildren) {
|
|
15744
|
-
|
|
15745
|
-
|
|
15746
|
-
|
|
15747
|
-
} catch {}
|
|
15748
|
-
}
|
|
15677
|
+
try {
|
|
15678
|
+
this.contentBox.remove(child);
|
|
15679
|
+
} catch {}
|
|
15749
15680
|
}
|
|
15750
15681
|
this.contentBox.add(new TextRenderable11(this.cliRenderer, {
|
|
15751
15682
|
content: `Configuring *arr applications...
|
|
@@ -15922,20 +15853,18 @@ class AppConfigurator extends BoxRenderable12 {
|
|
|
15922
15853
|
clear() {
|
|
15923
15854
|
const children = [...this.getChildren()];
|
|
15924
15855
|
for (const child of children) {
|
|
15925
|
-
|
|
15926
|
-
|
|
15927
|
-
|
|
15928
|
-
} catch {}
|
|
15929
|
-
}
|
|
15856
|
+
try {
|
|
15857
|
+
this.remove(child);
|
|
15858
|
+
} catch {}
|
|
15930
15859
|
}
|
|
15931
15860
|
}
|
|
15932
15861
|
destroy() {
|
|
15933
15862
|
if (this.keyHandler) {
|
|
15934
15863
|
this.cliRenderer.keyInput.off("keypress", this.keyHandler);
|
|
15935
15864
|
}
|
|
15936
|
-
if (this.parent
|
|
15865
|
+
if (this.parent) {
|
|
15937
15866
|
try {
|
|
15938
|
-
this.parent.remove(this
|
|
15867
|
+
this.parent.remove(this);
|
|
15939
15868
|
} catch {}
|
|
15940
15869
|
}
|
|
15941
15870
|
}
|
|
@@ -16098,8 +16027,7 @@ class LogsViewer extends BoxRenderable13 {
|
|
|
16098
16027
|
clearContent() {
|
|
16099
16028
|
const children = [...this.content.getChildren()];
|
|
16100
16029
|
for (const child of children) {
|
|
16101
|
-
|
|
16102
|
-
this.content.remove(child.id);
|
|
16030
|
+
this.content.remove(child);
|
|
16103
16031
|
}
|
|
16104
16032
|
}
|
|
16105
16033
|
renderContent() {
|
|
@@ -16297,7 +16225,7 @@ Start containers first to view logs.`,
|
|
|
16297
16225
|
}
|
|
16298
16226
|
rebuildUI() {
|
|
16299
16227
|
if (this.page) {
|
|
16300
|
-
this.remove(this.page
|
|
16228
|
+
this.remove(this.page);
|
|
16301
16229
|
}
|
|
16302
16230
|
this.buildUI();
|
|
16303
16231
|
}
|
|
@@ -16414,9 +16342,9 @@ import {
|
|
|
16414
16342
|
TabSelectRenderableEvents as TabSelectRenderableEvents2,
|
|
16415
16343
|
TextRenderable as TextRenderable13
|
|
16416
16344
|
} from "@opentui/core";
|
|
16417
|
-
init_registry();
|
|
16418
16345
|
init_manager();
|
|
16419
16346
|
init_schema();
|
|
16347
|
+
init_env();
|
|
16420
16348
|
var DEFAULT_CHECKS = {
|
|
16421
16349
|
health: true,
|
|
16422
16350
|
diskspace: true,
|
|
@@ -16604,7 +16532,7 @@ class MonitorDashboard extends BoxRenderable14 {
|
|
|
16604
16532
|
}
|
|
16605
16533
|
clearPanel(panel) {
|
|
16606
16534
|
const children = panel.getChildren();
|
|
16607
|
-
children.forEach((c) => panel.remove(c
|
|
16535
|
+
children.forEach((c) => panel.remove(c));
|
|
16608
16536
|
}
|
|
16609
16537
|
renderCategoriesPanel() {
|
|
16610
16538
|
this.clearPanel(this.categoriesPanel);
|
|
@@ -16863,8 +16791,7 @@ Press 'r' to refresh`,
|
|
|
16863
16791
|
const selectedApp = apps[this.appIndex];
|
|
16864
16792
|
if (!selectedApp)
|
|
16865
16793
|
return;
|
|
16866
|
-
const
|
|
16867
|
-
const env = await readEnv2();
|
|
16794
|
+
const env = await readEnv();
|
|
16868
16795
|
const apiKey = env[`API_KEY_${selectedApp.id.toUpperCase()}`];
|
|
16869
16796
|
if (!apiKey) {
|
|
16870
16797
|
this.statusData.set(selectedApp.id, {
|
|
@@ -17046,9 +16973,9 @@ Press 'r' to refresh`,
|
|
|
17046
16973
|
}
|
|
17047
16974
|
cleanup() {
|
|
17048
16975
|
this._renderer.keyInput.off("keypress", this.keyHandler);
|
|
17049
|
-
if (this.parent
|
|
16976
|
+
if (this.parent) {
|
|
17050
16977
|
try {
|
|
17051
|
-
this.parent.remove(this
|
|
16978
|
+
this.parent.remove(this);
|
|
17052
16979
|
} catch {}
|
|
17053
16980
|
}
|
|
17054
16981
|
}
|
|
@@ -17109,7 +17036,7 @@ class SettingsScreen extends BoxRenderable15 {
|
|
|
17109
17036
|
}
|
|
17110
17037
|
const children = this.getChildren();
|
|
17111
17038
|
for (const child of children) {
|
|
17112
|
-
this.remove(child
|
|
17039
|
+
this.remove(child);
|
|
17113
17040
|
}
|
|
17114
17041
|
const { container: page, content } = createPageLayout(this.cliRenderer, {
|
|
17115
17042
|
title: "Settings",
|
|
@@ -17542,7 +17469,7 @@ class SettingsScreen extends BoxRenderable15 {
|
|
|
17542
17469
|
}
|
|
17543
17470
|
const parent = this.parent;
|
|
17544
17471
|
if (parent) {
|
|
17545
|
-
parent.remove(this
|
|
17472
|
+
parent.remove(this);
|
|
17546
17473
|
}
|
|
17547
17474
|
}
|
|
17548
17475
|
}
|
|
@@ -18997,7 +18924,6 @@ class QualityProfileClient {
|
|
|
18997
18924
|
}
|
|
18998
18925
|
|
|
18999
18926
|
// src/setup/actions/arr-common.ts
|
|
19000
|
-
init_registry();
|
|
19001
18927
|
init_debug();
|
|
19002
18928
|
|
|
19003
18929
|
// src/utils/url-utils.ts
|
|
@@ -19054,6 +18980,8 @@ async function setupArrRootFolders(ctx) {
|
|
|
19054
18980
|
const options = { path: def.rootFolder.path };
|
|
19055
18981
|
if (app.id === "lidarr")
|
|
19056
18982
|
options.name = "Music";
|
|
18983
|
+
if (app.id === "readarr")
|
|
18984
|
+
options.name = "Books";
|
|
19057
18985
|
await client.addRootFolder(options);
|
|
19058
18986
|
configured++;
|
|
19059
18987
|
}
|
|
@@ -19499,7 +19427,6 @@ class JellyseerrClient extends BaseApiClient {
|
|
|
19499
19427
|
}
|
|
19500
19428
|
|
|
19501
19429
|
// src/setup/actions/jellyseerr.ts
|
|
19502
|
-
init_registry();
|
|
19503
19430
|
init_debug();
|
|
19504
19431
|
async function checkJellyseerrPrerequisites(ctx) {
|
|
19505
19432
|
const jellyseerrConfig = getEnabledAppConfig(ctx, "jellyseerr");
|
|
@@ -19996,7 +19923,6 @@ var PROWLARR_CATEGORIES = [
|
|
|
19996
19923
|
];
|
|
19997
19924
|
|
|
19998
19925
|
// src/setup/actions/prowlarr.ts
|
|
19999
|
-
init_registry();
|
|
20000
19926
|
var ARR_APP_TYPES = {
|
|
20001
19927
|
radarr: "Radarr",
|
|
20002
19928
|
sonarr: "Sonarr",
|
|
@@ -23568,7 +23494,6 @@ Object.assign(lookup, {
|
|
|
23568
23494
|
});
|
|
23569
23495
|
|
|
23570
23496
|
// src/api/uptime-kuma-api.ts
|
|
23571
|
-
init_registry();
|
|
23572
23497
|
init_debug();
|
|
23573
23498
|
|
|
23574
23499
|
class UptimeKumaClient {
|
|
@@ -23874,7 +23799,6 @@ async function setupTautulli(ctx) {
|
|
|
23874
23799
|
}
|
|
23875
23800
|
}
|
|
23876
23801
|
// src/api/heimdall-api.ts
|
|
23877
|
-
init_registry();
|
|
23878
23802
|
class HeimdallClient extends BaseApiClient {
|
|
23879
23803
|
logPrefix = "HeimdallApi";
|
|
23880
23804
|
constructor(host, port = 80) {
|
|
@@ -23960,7 +23884,6 @@ class HeimdallClient extends BaseApiClient {
|
|
|
23960
23884
|
}
|
|
23961
23885
|
|
|
23962
23886
|
// src/api/homarr-api.ts
|
|
23963
|
-
init_registry();
|
|
23964
23887
|
init_debug();
|
|
23965
23888
|
class HomarrClient extends BaseApiClient {
|
|
23966
23889
|
logPrefix = "HomarrApi";
|
|
@@ -24385,13 +24308,12 @@ class HuntarrClient extends BaseApiClient {
|
|
|
24385
24308
|
return { success: false, message: "Huntarr not reachable" };
|
|
24386
24309
|
}
|
|
24387
24310
|
const version = await this.getVersion();
|
|
24388
|
-
const { getApp: getApp2 } = await Promise.resolve().then(() => (init_registry(), exports_registry));
|
|
24389
24311
|
for (const appType of HUNTARR_APP_TYPES) {
|
|
24390
24312
|
const apiKeyEnvName = `API_KEY_${appType.toUpperCase()}`;
|
|
24391
24313
|
const apiKey = env[apiKeyEnvName];
|
|
24392
24314
|
if (!apiKey)
|
|
24393
24315
|
continue;
|
|
24394
|
-
const appDef =
|
|
24316
|
+
const appDef = getApp(appType);
|
|
24395
24317
|
const port = appDef?.defaultPort ?? 8989;
|
|
24396
24318
|
const apiUrl = `http://${appType}:${port}`;
|
|
24397
24319
|
const result = await this.testConnection(appType, apiUrl, apiKey);
|
|
@@ -24428,7 +24350,6 @@ class HuntarrClient extends BaseApiClient {
|
|
|
24428
24350
|
}
|
|
24429
24351
|
async setupEasiarrApps(apps, env) {
|
|
24430
24352
|
const results = [];
|
|
24431
|
-
const { getApp: getApp2 } = await Promise.resolve().then(() => (init_registry(), exports_registry));
|
|
24432
24353
|
for (const appConfig of apps) {
|
|
24433
24354
|
if (!appConfig.enabled)
|
|
24434
24355
|
continue;
|
|
@@ -24438,7 +24359,7 @@ class HuntarrClient extends BaseApiClient {
|
|
|
24438
24359
|
const apiKey = env[`API_KEY_${appType.toUpperCase()}`];
|
|
24439
24360
|
if (!apiKey)
|
|
24440
24361
|
continue;
|
|
24441
|
-
const appDef =
|
|
24362
|
+
const appDef = getApp(appType);
|
|
24442
24363
|
const port = appDef?.defaultPort ?? 8989;
|
|
24443
24364
|
const apiUrl = `http://${appType}:${port}`;
|
|
24444
24365
|
const instanceName = appDef?.name ?? appType;
|
|
@@ -24453,7 +24374,7 @@ class HuntarrClient extends BaseApiClient {
|
|
|
24453
24374
|
if (prowlarrConfig) {
|
|
24454
24375
|
const prowlarrApiKey = env["API_KEY_PROWLARR"];
|
|
24455
24376
|
if (prowlarrApiKey) {
|
|
24456
|
-
const prowlarrDef =
|
|
24377
|
+
const prowlarrDef = getApp("prowlarr");
|
|
24457
24378
|
const prowlarrPort = prowlarrConfig.port || prowlarrDef?.defaultPort || 9696;
|
|
24458
24379
|
const prowlarrUrl = `http://prowlarr:${prowlarrPort}`;
|
|
24459
24380
|
const configured = await this.configureProwlarr(prowlarrUrl, prowlarrApiKey);
|
|
@@ -25234,9 +25155,6 @@ class ProfilarrApiClient {
|
|
|
25234
25155
|
}
|
|
25235
25156
|
}
|
|
25236
25157
|
|
|
25237
|
-
// src/setup/actions/utilities.ts
|
|
25238
|
-
init_registry();
|
|
25239
|
-
|
|
25240
25158
|
// src/config/slskd-config.ts
|
|
25241
25159
|
init_env();
|
|
25242
25160
|
import { randomBytes as randomBytes2 } from "crypto";
|
|
@@ -26270,7 +26188,6 @@ Press Enter to go back.
|
|
|
26270
26188
|
}
|
|
26271
26189
|
|
|
26272
26190
|
// src/ui/screens/setup/HomepageSetup.ts
|
|
26273
|
-
init_registry();
|
|
26274
26191
|
import { TextRenderable as TextRenderable18 } from "@opentui/core";
|
|
26275
26192
|
class HomepageSetup extends BaseAppSetupScreen {
|
|
26276
26193
|
previewContent = "";
|
|
@@ -26832,7 +26749,6 @@ class JellyseerrSetup extends BaseAppSetupScreen {
|
|
|
26832
26749
|
|
|
26833
26750
|
// src/ui/screens/setup/ProwlarrSetup.ts
|
|
26834
26751
|
import { TextNodeRenderable as TextNodeRenderable2, TextRenderable as TextRenderable21 } from "@opentui/core";
|
|
26835
|
-
init_registry();
|
|
26836
26752
|
init_env();
|
|
26837
26753
|
var ARR_APP_TYPES2 = {
|
|
26838
26754
|
radarr: "Radarr",
|
|
@@ -27970,9 +27886,6 @@ function getCFNamesForCategories(app, categories) {
|
|
|
27970
27886
|
return categories.flatMap((cat) => cfNames[cat] || []);
|
|
27971
27887
|
}
|
|
27972
27888
|
|
|
27973
|
-
// src/ui/screens/setup/TRaSHProfileSetup.ts
|
|
27974
|
-
init_registry();
|
|
27975
|
-
|
|
27976
27889
|
// src/data/lidarr-custom-formats.ts
|
|
27977
27890
|
var CF_PREFERRED_GROUPS = {
|
|
27978
27891
|
name: "Preferred Groups",
|
|
@@ -28676,7 +28589,7 @@ class QuickSetup {
|
|
|
28676
28589
|
}
|
|
28677
28590
|
const children = this.container.getChildren();
|
|
28678
28591
|
for (const child of children) {
|
|
28679
|
-
this.container.remove(child
|
|
28592
|
+
this.container.remove(child);
|
|
28680
28593
|
}
|
|
28681
28594
|
switch (this.step) {
|
|
28682
28595
|
case "welcome":
|
|
@@ -28806,7 +28719,7 @@ class QuickSetup {
|
|
|
28806
28719
|
}
|
|
28807
28720
|
const children = this.container.getChildren();
|
|
28808
28721
|
for (const child of children) {
|
|
28809
|
-
this.container.remove(child
|
|
28722
|
+
this.container.remove(child);
|
|
28810
28723
|
}
|
|
28811
28724
|
const { container: page, content } = createPageLayout(this.renderer, {
|
|
28812
28725
|
title: "About easiarr",
|
|
@@ -29645,7 +29558,7 @@ class App {
|
|
|
29645
29558
|
this.currentScreen = screen;
|
|
29646
29559
|
const children = this.screenContainer.getChildren();
|
|
29647
29560
|
for (const child of children) {
|
|
29648
|
-
this.screenContainer.remove(child
|
|
29561
|
+
this.screenContainer.remove(child);
|
|
29649
29562
|
}
|
|
29650
29563
|
switch (screen) {
|
|
29651
29564
|
case "main":
|