diff --git a/assets/the_man.png b/assets/the_man.png
new file mode 100644
index 0000000..e9ba611
Binary files /dev/null and b/assets/the_man.png differ
diff --git a/module.nix b/module.nix
index 3e11613..50b7bc9 100644
--- a/module.nix
+++ b/module.nix
@@ -14,6 +14,8 @@ in
 
     enablePipewire = lib.mkEnableOption "pipewire" // { default = true; };
 
+    enableDebug = lib.mkEnableOption "debug logs";
+
     # TODO: create some better descriptions
     settings = {
       host = lib.mkOption {
@@ -81,25 +83,52 @@ in
 
   config = lib.mkMerge [
     (lib.mkIf cfg.enable {
-      users = {
-        users.greg = {
-          isNormalUser = true;
-          group = "greg";
-          uid = 2000;
-          description = "loud gym bro";
-        };
-        groups.greg.gid = 2000;
-      };
-
       systemd.user.services.greg-ng = {
         description = "greg-ng, an mpv based media player";
         wantedBy = [ "graphical-session.target" ];
         partOf = [ "graphical-session.target" ];
+        environment.RUST_LOG = lib.mkIf cfg.enableDebug "greg_ng=trace,mpvipc=trace";
         serviceConfig = {
           Type = "simple";
           ExecStart = "${lib.getExe cfg.package} ${lib.cli.toGNUCommandLineShell { } cfg.settings}";
           Restart = "always";
           RestartSec = 3;
+
+          RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" "AF_INET6" ];
+          AmbientCapabilities = [ "" ];
+          CapabilityBoundingSet = [ "" ];
+          DeviceAllow = [ "" ];
+          LockPersonality = true;
+          # Might work, but wouldn't bet on it with embedded lua in mpv
+          MemoryDenyWriteExecute = false;
+          NoNewPrivileges = true;
+          # MPV and mesa tries to talk directly to the GPU.
+          PrivateDevices = false;
+          PrivateMounts = true;
+          PrivateTmp = true;
+          PrivateUsers = true;
+          ProcSubset = "pid";
+          ProtectClock = true;
+          ProtectControlGroups = true;
+          # MPV wants ~/.cache
+          ProtectHome = false;
+          ProtectHostname = true;
+          ProtectKernelLogs = true;
+          ProtectKernelModules = true;
+          ProtectKernelTunables = true;
+          ProtectProc = "invisible";
+          ProtectSystem = "full";
+          RemoveIPC = true;
+          UMask = "0077";
+          RestrictNamespaces = true;
+          RestrictRealtime = true;
+          RestrictSUIDSGID = true;
+          SystemCallArchitectures = "native";
+          SystemCallFilter = [
+            "@system-service"
+            "~@privileged"
+            "~@resources"
+          ];
         };
       };
     })
@@ -123,6 +152,16 @@ in
         extraPortals = [ pkgs.xdg-desktop-portal-gtk ];
       };
 
+      users = {
+        users.greg = {
+          isNormalUser = true;
+          group = "greg";
+          uid = 2000;
+          description = "loud gym bro";
+        };
+        groups.greg.gid = 2000;
+      };
+
       services.greetd = {
         enable = true;
         settings = rec {
diff --git a/src/main.rs b/src/main.rs
index 35fb514..9def7d5 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,17 +1,12 @@
 use anyhow::Context;
 use axum::{Router, Server};
 use clap::Parser;
-use mpvipc_async::Mpv;
-use std::{
-    fs::create_dir_all,
-    io::Write,
-    net::{IpAddr, SocketAddr},
-    path::Path,
-};
+use mpv_setup::{connect_to_mpv, create_mpv_config_file, show_grzegorz_image};
+use std::net::{IpAddr, SocketAddr};
 use tempfile::NamedTempFile;
-use tokio::process::{Child, Command};
 
 mod api;
+mod mpv_setup;
 
 #[derive(Parser)]
 struct Args {
@@ -45,112 +40,6 @@ struct MpvConnectionArgs<'a> {
     force_auto_start: bool,
 }
 
-const DEFAULT_MPV_CONFIG_CONTENT: &str = include_str!("../assets/default-mpv.conf");
-
-fn create_mpv_config_file(args_config_file: Option<String>) -> anyhow::Result<NamedTempFile> {
-    let file_content = if let Some(path) = args_config_file {
-        if !Path::new(&path).exists() {
-            anyhow::bail!("Mpv config file not found at {}", &path);
-        }
-
-        std::fs::read_to_string(&path).context("Failed to read mpv config file")?
-    } else {
-        DEFAULT_MPV_CONFIG_CONTENT.to_string()
-    };
-
-    let tmpfile = tempfile::Builder::new()
-        .prefix("mpv-")
-        .rand_bytes(8)
-        .suffix(".conf")
-        .tempfile()?;
-
-    tmpfile.reopen()?.write_all(file_content.as_bytes())?;
-
-    Ok(tmpfile)
-}
-
-async fn connect_to_mpv<'a>(args: &MpvConnectionArgs<'a>) -> anyhow::Result<(Mpv, Option<Child>)> {
-    log::debug!("Connecting to mpv");
-
-    debug_assert!(
-        !args.force_auto_start || args.auto_start,
-        "force_auto_start requires auto_start"
-    );
-
-    let socket_path = Path::new(&args.socket_path);
-
-    if !socket_path.exists() {
-        log::debug!("Mpv socket not found at {}", &args.socket_path);
-        if !args.auto_start {
-            panic!("Mpv socket not found at {}", &args.socket_path);
-        }
-
-        log::debug!("Ensuring parent dir of mpv socket exists");
-        let parent_dir = Path::new(&args.socket_path)
-            .parent()
-            .context("Failed to get parent dir of mpv socket")?;
-
-        if !parent_dir.is_dir() {
-            create_dir_all(parent_dir).context("Failed to create parent dir of mpv socket")?;
-        }
-    } else {
-        log::debug!("Existing mpv socket found at {}", &args.socket_path);
-        if args.force_auto_start {
-            log::debug!("Removing mpv socket");
-            std::fs::remove_file(&args.socket_path)?;
-        }
-    }
-
-    let process_handle = if args.auto_start {
-        log::info!("Starting mpv with socket at {}", &args.socket_path);
-
-        // TODO: try to fetch mpv from PATH
-        Some(
-            Command::new(args.executable_path.as_deref().unwrap_or("mpv"))
-                .arg(format!("--input-ipc-server={}", &args.socket_path))
-                .arg("--idle")
-                .arg("--force-window")
-                .arg("--fullscreen")
-                .arg("--no-config")
-                .arg(format!(
-                    "--include={}",
-                    &args.config_file.path().to_string_lossy()
-                ))
-                // .arg("--no-terminal")
-                .arg("--load-unsafe-playlists")
-                .arg("--keep-open") // Keep last frame of video on end of video
-                .spawn()
-                .context("Failed to start mpv")?,
-        )
-    } else {
-        None
-    };
-
-    // Wait for mpv to create the socket
-    if tokio::time::timeout(tokio::time::Duration::from_millis(500), async {
-        while !&socket_path.exists() {
-            log::debug!("Waiting for mpv socket at {}", &args.socket_path);
-            tokio::time::sleep(tokio::time::Duration::from_millis(10)).await;
-        }
-    })
-    .await
-    .is_err()
-    {
-        return Err(anyhow::anyhow!(
-            "Failed to connect to mpv socket: {}",
-            &args.socket_path
-        ));
-    }
-
-    Ok((
-        Mpv::connect(&args.socket_path).await.context(format!(
-            "Failed to connect to mpv socket: {}",
-            &args.socket_path
-        ))?,
-        process_handle,
-    ))
-}
-
 async fn resolve(host: &str) -> anyhow::Result<IpAddr> {
     let addr = format!("{}:0", host);
     let addresses = tokio::net::lookup_host(addr).await?;
@@ -177,6 +66,10 @@ async fn main() -> anyhow::Result<()> {
     })
     .await?;
 
+    if let Err(e) = show_grzegorz_image(mpv.clone()).await {
+      log::warn!("Could not show Grzegorz image: {}", e);
+    }
+
     let addr = SocketAddr::new(resolve(&args.host).await?, args.port);
     log::info!("Starting API on {}", addr);
 
diff --git a/src/mpv_setup.rs b/src/mpv_setup.rs
new file mode 100644
index 0000000..0ed40e2
--- /dev/null
+++ b/src/mpv_setup.rs
@@ -0,0 +1,135 @@
+use std::{fs::create_dir_all, io::Write, path::Path};
+
+use anyhow::Context;
+use mpvipc_async::{Mpv, MpvExt};
+use tempfile::NamedTempFile;
+use tokio::process::{Child, Command};
+
+use crate::MpvConnectionArgs;
+
+const DEFAULT_MPV_CONFIG_CONTENT: &str = include_str!("../assets/default-mpv.conf");
+
+const THE_MAN_PNG: &[u8] = include_bytes!("../assets/the_man.png");
+
+pub fn create_mpv_config_file(args_config_file: Option<String>) -> anyhow::Result<NamedTempFile> {
+    let file_content = if let Some(path) = args_config_file {
+        if !Path::new(&path).exists() {
+            anyhow::bail!("Mpv config file not found at {}", &path);
+        }
+
+        std::fs::read_to_string(&path).context("Failed to read mpv config file")?
+    } else {
+        DEFAULT_MPV_CONFIG_CONTENT.to_string()
+    };
+
+    let tmpfile = tempfile::Builder::new()
+        .prefix("mpv-")
+        .rand_bytes(8)
+        .suffix(".conf")
+        .tempfile()?;
+
+    tmpfile.reopen()?.write_all(file_content.as_bytes())?;
+
+    Ok(tmpfile)
+}
+
+pub async fn connect_to_mpv<'a>(
+    args: &MpvConnectionArgs<'a>,
+) -> anyhow::Result<(Mpv, Option<Child>)> {
+    log::debug!("Connecting to mpv");
+
+    debug_assert!(
+        !args.force_auto_start || args.auto_start,
+        "force_auto_start requires auto_start"
+    );
+
+    let socket_path = Path::new(&args.socket_path);
+
+    if !socket_path.exists() {
+        log::debug!("Mpv socket not found at {}", &args.socket_path);
+        if !args.auto_start {
+            panic!("Mpv socket not found at {}", &args.socket_path);
+        }
+
+        log::debug!("Ensuring parent dir of mpv socket exists");
+        let parent_dir = Path::new(&args.socket_path)
+            .parent()
+            .context("Failed to get parent dir of mpv socket")?;
+
+        if !parent_dir.is_dir() {
+            create_dir_all(parent_dir).context("Failed to create parent dir of mpv socket")?;
+        }
+    } else {
+        log::debug!("Existing mpv socket found at {}", &args.socket_path);
+        if args.force_auto_start {
+            log::debug!("Removing mpv socket");
+            std::fs::remove_file(&args.socket_path)?;
+        }
+    }
+
+    let process_handle = if args.auto_start {
+        log::info!("Starting mpv with socket at {}", &args.socket_path);
+
+        // TODO: try to fetch mpv from PATH
+        Some(
+            Command::new(args.executable_path.as_deref().unwrap_or("mpv"))
+                .arg(format!("--input-ipc-server={}", &args.socket_path))
+                .arg("--idle")
+                .arg("--force-window")
+                .arg("--fullscreen")
+                .arg("--no-config")
+                .arg(format!(
+                    "--include={}",
+                    &args.config_file.path().to_string_lossy()
+                ))
+                // .arg("--no-terminal")
+                .arg("--load-unsafe-playlists")
+                .arg("--keep-open") // Keep last frame of video on end of video
+                .spawn()
+                .context("Failed to start mpv")?,
+        )
+    } else {
+        None
+    };
+
+    // Wait for mpv to create the socket
+    if tokio::time::timeout(tokio::time::Duration::from_millis(500), async {
+        while !&socket_path.exists() {
+            log::debug!("Waiting for mpv socket at {}", &args.socket_path);
+            tokio::time::sleep(tokio::time::Duration::from_millis(10)).await;
+        }
+    })
+    .await
+    .is_err()
+    {
+        return Err(anyhow::anyhow!(
+            "Failed to connect to mpv socket: {}",
+            &args.socket_path
+        ));
+    }
+
+    Ok((
+        Mpv::connect(&args.socket_path).await.context(format!(
+            "Failed to connect to mpv socket: {}",
+            &args.socket_path
+        ))?,
+        process_handle,
+    ))
+}
+
+pub async fn show_grzegorz_image(mpv: Mpv) -> anyhow::Result<()> {
+    let path = std::env::temp_dir().join("the_man.png");
+    std::fs::write(path.as_path(), THE_MAN_PNG)?;
+
+    mpv.playlist_clear().await?;
+    mpv.playlist_add(
+        path.to_string_lossy().as_ref(),
+        mpvipc_async::PlaylistAddTypeOptions::File,
+        mpvipc_async::PlaylistAddOptions::Append,
+    )
+    .await?;
+    mpv.next().await?;
+
+    Ok(())
+}
+