Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,10 +124,13 @@ Here is the matrix of deployed services:
| | DNSCrypt Proxy | 5300 | `dnscrypt-proxy` | Secure DNS (DoH) |
| | Wireguard | 51820 (UDP) | - | VPN |
| **Media** | Plex | 32400 | `http://IP:32400` | Streaming Server |
| | Jellyfin | 8096 | `http://IP:8096` | Streaming Server (Open Source) |
| | Tautulli | 8181 | `http://IP:8181` | Plex Stats |
| | Overseerr | 5055 | `http://IP:5055` | Media Requests |
| | Overseerr | 5055 | `http://IP:5055` | Plex Requests |
| | Jellyseerr | 5056 | `http://IP:5056` | Jellyfin Requests |
| **ArrStack** | Sonarr | 8989 | `http://IP:8989` | TV Shows |
| | Radarr | 7878 | `http://IP:7878` | Movies |
| | Bazarr | 6767 | `http://IP:6767` | Subtitles |
| | Prowlarr | 9696 | `http://IP:9696` | Torrent Indexers |
| | Jackett | 9117 | `http://IP:9117` | Indexer Proxy |
| **Download** | QBittorrent | 8080 | `http://IP:8080` | Torrent Client |
Expand Down Expand Up @@ -242,10 +245,13 @@ Voici la matrice des services déployés :
| | DNSCrypt Proxy | 5300 | `dnscrypt-proxy` | DNS Sécurisé (DoH) |
| | Wireguard | 51820 (UDP) | - | VPN |
| **Média** | Plex | 32400 | `http://IP:32400` | Serveur Streaming |
| | Jellyfin | 8096 | `http://IP:8096` | Serveur Streaming (Open Source) |
| | Tautulli | 8181 | `http://IP:8181` | Stats Plex |
| | Overseerr | 5055 | `http://IP:5055` | Demandes de Média |
| | Overseerr | 5055 | `http://IP:5055` | Demandes Plex |
| | Jellyseerr | 5056 | `http://IP:5056` | Demandes Jellyfin |
| **ArrStack** | Sonarr | 8989 | `http://IP:8989` | Séries TV |
| | Radarr | 7878 | `http://IP:7878` | Films |
| | Bazarr | 6767 | `http://IP:6767` | Sous-titres |
| | Prowlarr | 9696 | `http://IP:9696` | Indexeurs Torrent |
| | Jackett | 9117 | `http://IP:9117` | Proxy Indexeurs |
| **Download** | QBittorrent | 8080 | `http://IP:8080` | Client Torrent |
Expand Down
1 change: 1 addition & 0 deletions server_manager/src/services/arr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,4 @@ define_arr_service!(SonarrService, "sonarr", "lscr.io/linuxserver/sonarr:latest"
define_arr_service!(RadarrService, "radarr", "lscr.io/linuxserver/radarr:latest", 7878);
define_arr_service!(ProwlarrService, "prowlarr", "lscr.io/linuxserver/prowlarr:latest", 9696);
define_arr_service!(JackettService, "jackett", "lscr.io/linuxserver/jackett:latest", 9117);
define_arr_service!(BazarrService, "bazarr", "lscr.io/linuxserver/bazarr:latest", 6767);
84 changes: 84 additions & 0 deletions server_manager/src/services/media.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,90 @@ impl Service for PlexService {
}
}

pub struct JellyfinService;

impl Service for JellyfinService {
fn name(&self) -> &'static str { "jellyfin" }
fn image(&self) -> &'static str { "lscr.io/linuxserver/jellyfin:latest" }

fn ports(&self) -> Vec<String> {
vec!["8096:8096".to_string()]
}

fn env_vars(&self, hw: &HardwareInfo, _secrets: &Secrets) -> HashMap<String, String> {
let mut vars = HashMap::new();
vars.insert("PUID".to_string(), hw.user_id.clone());
vars.insert("PGID".to_string(), hw.group_id.clone());

if hw.has_nvidia {
vars.insert("NVIDIA_VISIBLE_DEVICES".to_string(), "all".to_string());
vars.insert("NVIDIA_DRIVER_CAPABILITIES".to_string(), "compute,video,utility".to_string());
}

vars
}

fn volumes(&self, hw: &HardwareInfo) -> Vec<String> {
let mut vols = vec![
"./config/jellyfin:/config".to_string(),
"./media/tv:/data/tvshows".to_string(),
"./media/movies:/data/movies".to_string(),
];

// Optimization: RAM Transcoding for High Profile
match hw.profile {
HardwareProfile::High => vols.push("/dev/shm:/transcode".to_string()),
_ => vols.push("./transcode_jellyfin:/transcode".to_string()),
}

vols
}

fn devices(&self, hw: &HardwareInfo) -> Vec<String> {
if hw.has_intel_quicksync {
return vec!["/dev/dri:/dev/dri".to_string()];
}
vec![]
}

fn healthcheck(&self) -> Option<String> {
Some("curl -f http://localhost:8096/health || exit 1".to_string())
}

fn resources(&self, hw: &HardwareInfo) -> Option<ResourceConfig> {
let memory_limit = match hw.profile {
HardwareProfile::High => "8G",
HardwareProfile::Standard => "4G",
HardwareProfile::Low => "2G",
};
Some(ResourceConfig {
memory_limit: Some(memory_limit.to_string()),
memory_reservation: None,
cpu_limit: None,
cpu_reservation: None,
})
}
}

pub struct JellyseerrService;
impl Service for JellyseerrService {
fn name(&self) -> &'static str { "jellyseerr" }
fn image(&self) -> &'static str { "fallenbagel/jellyseerr:latest" }
// Internal port 5055, exposed as 5056 to avoid conflict with Overseerr
fn ports(&self) -> Vec<String> { vec!["127.0.0.1:5056:5055".to_string()] }
fn volumes(&self, _hw: &HardwareInfo) -> Vec<String> {
vec!["./config/jellyseerr:/app/config".to_string()]
}
fn resources(&self, _hw: &HardwareInfo) -> Option<ResourceConfig> {
Some(ResourceConfig {
memory_limit: Some("1G".to_string()),
memory_reservation: None,
cpu_limit: None,
cpu_reservation: None,
})
}
}

pub struct TautulliService;
impl Service for TautulliService {
fn name(&self) -> &'static str { "tautulli" }
Expand Down
3 changes: 3 additions & 0 deletions server_manager/src/services/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,13 @@ pub fn get_all_services() -> Vec<Box<dyn Service>> {
Box::new(media::PlexService),
Box::new(media::TautulliService),
Box::new(media::OverseerrService),
Box::new(media::JellyfinService),
Box::new(media::JellyseerrService),
Box::new(arr::SonarrService),
Box::new(arr::RadarrService),
Box::new(arr::ProwlarrService),
Box::new(arr::JackettService),
Box::new(arr::BazarrService),
Box::new(download::QBittorrentService),
Box::new(infra::MariaDBService),
Box::new(infra::RedisService),
Expand Down
8 changes: 5 additions & 3 deletions server_manager/tests/integration_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,14 @@ fn test_generate_compose_structure() {
let networks = mapping.get(&serde_yaml::Value::from("networks")).unwrap().as_mapping().unwrap();
assert!(networks.contains_key(&serde_yaml::Value::from("server_manager_net")));

// 5. Verify Services Count (Should be 24)
// 5. Verify Services Count (Should be 27)
let services = mapping.get(&serde_yaml::Value::from("services")).unwrap().as_mapping().unwrap();
assert_eq!(services.len(), 24, "Expected 24 services");
assert_eq!(services.len(), 27, "Expected 27 services");

// 6. Verify specific service (Plex)
// 6. Verify specific service (Plex, Jellyfin, Bazarr)
assert!(services.contains_key(&serde_yaml::Value::from("plex")));
assert!(services.contains_key(&serde_yaml::Value::from("jellyfin")));
assert!(services.contains_key(&serde_yaml::Value::from("bazarr")));
let plex = services.get(&serde_yaml::Value::from("plex")).unwrap().as_mapping().unwrap();
assert_eq!(plex.get(&serde_yaml::Value::from("image")).unwrap().as_str().unwrap(), "lscr.io/linuxserver/plex:latest");

Expand Down