diff --git a/ansible/roles/sunshine/templates/docker-compose.yml b/ansible/roles/sunshine/templates/docker-compose.yml
index ac12c2ed..1bb9c140 100644
--- a/ansible/roles/sunshine/templates/docker-compose.yml
+++ b/ansible/roles/sunshine/templates/docker-compose.yml
@@ -46,6 +46,7 @@ services:
- "47989:47989/tcp" # HTTP
- "47990:47990/tcp" # Web
- "48010:48010/tcp" # RTSP
+ - "59999:59999/tcp" # MoonDeckBuddy
- "47998:47998/udp" # Video
- "47999:47999/udp" # Control
diff --git a/containers/sunshine/Dockerfile b/containers/sunshine/Dockerfile
index 93ba2791..0547afe7 100644
--- a/containers/sunshine/Dockerfile
+++ b/containers/sunshine/Dockerfile
@@ -28,7 +28,13 @@ FROM download-base AS download-heroic
ARG HEROIC_VERSION="2.18.1"
RUN curl -L -o /app/heroic.deb "https://github.com/Heroic-Games-Launcher/HeroicGamesLauncher/releases/download/v${HEROIC_VERSION}/Heroic-${HEROIC_VERSION}-linux-amd64.deb"
-#
+# MoonDeckBuddy
+# https://github.com/FrogTheFrog/moondeck-buddy/releases
+FROM download-base AS download-moondeckbuddy
+ARG MOONDECKBUDDY_VERSION="1.9.2"
+RUN curl -L -o /app/MoonDeckBuddy.AppImage "https://github.com/FrogTheFrog/moondeck-buddy/releases/download/v${MOONDECKBUDDY_VERSION}/MoonDeckBuddy-${MOONDECKBUDDY_VERSION}-x86_64.AppImage"
+
+#
# Sunshine image based on Ubuntu 24.04
# with desktop environment, game launchers and dependencies
#
@@ -38,9 +44,9 @@ ENV DEBIAN_FRONTEND=noninteractive
RUN --mount=type=cache,target=/var/cache --mount=type=tmpfs,target=/var/log <<_MAIN_PACKAGES
-set -e
+set -e
-# Required for some Steam packages
+# Required for some Steam packages
dpkg --add-architecture i386
apt update
@@ -84,6 +90,8 @@ apt install -y \
xz-utils \
zenity \
bubblewrap \
+ fuse3 \
+ libfuse2t64 \
software-properties-common \
nano \
unzip \
@@ -272,7 +280,21 @@ ENV DBUS_SYSTEM_BUS_ADDRESS="unix:path=$XDG_RUNTIME_DIR/dbus"
# TODO use host UID/GID for better portability and usage from host ?
RUN useradd -m -d $CLOUDYPAD_USER_HOME -s /bin/bash -u 1001 $CLOUDYPAD_USER
-# Copy overlay files: startup scripts, default config, etc.
+# Install MoonDeckBuddy AppImage
+RUN --mount=type=bind,from=download-moondeckbuddy,source=/app,target=/app <<_MOONDECKBUDDY
+
+set -e
+
+MOONDECKBUDDY_APP_DIR="/opt/MoonDeckBuddy"
+MOONDECKBUDDY_APPIMAGE_PATH="${MOONDECKBUDDY_APP_DIR}/MoonDeckBuddy.AppImage"
+
+install -d -o "${CLOUDYPAD_USER}" -g "${CLOUDYPAD_USER}" "${MOONDECKBUDDY_APP_DIR}"
+install -m 0755 -o "${CLOUDYPAD_USER}" -g "${CLOUDYPAD_USER}" /app/MoonDeckBuddy.AppImage "${MOONDECKBUDDY_APPIMAGE_PATH}"
+ln -sf "${MOONDECKBUDDY_APPIMAGE_PATH}" /usr/local/bin/MoonDeckBuddy
+
+_MOONDECKBUDDY
+
+# Copy overlay files: startup scripts, default config, etc.
COPY overlay /
# Run healthcheck using script
diff --git a/containers/sunshine/overlay/cloudy/bin/moondeckstream-start.sh b/containers/sunshine/overlay/cloudy/bin/moondeckstream-start.sh
new file mode 100644
index 00000000..804feeab
--- /dev/null
+++ b/containers/sunshine/overlay/cloudy/bin/moondeckstream-start.sh
@@ -0,0 +1,20 @@
+#!/usr/bin/env bash
+
+wait-x-availability.sh
+
+MOONDECKBUDDY_APPIMAGE_PATH="/opt/MoonDeckBuddy/MoonDeckBuddy.AppImage"
+
+if [ ! -x "$MOONDECKBUDDY_APPIMAGE_PATH" ]; then
+ echo "MoonDeckBuddy AppImage not found at $MOONDECKBUDDY_APPIMAGE_PATH"
+ exit 1
+fi
+
+cd "$CLOUDYPAD_USER_HOME"
+
+"$MOONDECKBUDDY_APPIMAGE_PATH" --exec MoonDeckStream &
+
+MOONDECKSTREAM_PID=$!
+echo $MOONDECKSTREAM_PID > /tmp/moondeckstream.pid
+echo "MoonDeckStream started with PID: $MOONDECKSTREAM_PID"
+
+wait $MOONDECKSTREAM_PID
diff --git a/containers/sunshine/overlay/cloudy/bin/moondeckstream-stop.sh b/containers/sunshine/overlay/cloudy/bin/moondeckstream-stop.sh
new file mode 100644
index 00000000..0f5130e4
--- /dev/null
+++ b/containers/sunshine/overlay/cloudy/bin/moondeckstream-stop.sh
@@ -0,0 +1,17 @@
+#!/usr/bin/env bash
+
+echo "Stopping MoonDeckStream..."
+
+if [ ! -f /tmp/moondeckstream.pid ]; then
+ echo "No MoonDeckStream PID found at /tmp/moondeckstream.pid... Not stopping."
+ exit 0
+fi
+
+MOONDECKSTREAM_PID=$(cat /tmp/moondeckstream.pid)
+
+echo "Killing MoonDeckStream with PID: $MOONDECKSTREAM_PID"
+
+# Kill MoonDeckStream processes
+kill $MOONDECKSTREAM_PID
+
+echo "MoonDeckStream stopped"
diff --git a/containers/sunshine/overlay/cloudy/bin/start-moondeckbuddy.sh b/containers/sunshine/overlay/cloudy/bin/start-moondeckbuddy.sh
new file mode 100755
index 00000000..510e2482
--- /dev/null
+++ b/containers/sunshine/overlay/cloudy/bin/start-moondeckbuddy.sh
@@ -0,0 +1,14 @@
+#!/usr/bin/env bash
+
+wait-x-availability.sh
+
+MOONDECKBUDDY_APPIMAGE_PATH="/opt/MoonDeckBuddy/MoonDeckBuddy.AppImage"
+
+if [ ! -x "$MOONDECKBUDDY_APPIMAGE_PATH" ]; then
+ echo "MoonDeckBuddy AppImage not found at $MOONDECKBUDDY_APPIMAGE_PATH"
+ exit 1
+fi
+
+cd "$CLOUDYPAD_USER_HOME"
+
+exec "$MOONDECKBUDDY_APPIMAGE_PATH"
diff --git a/containers/sunshine/overlay/cloudy/conf/sunshine/apps.json b/containers/sunshine/overlay/cloudy/conf/sunshine/apps.json
index b9bc2a92..819d60c5 100644
--- a/containers/sunshine/overlay/cloudy/conf/sunshine/apps.json
+++ b/containers/sunshine/overlay/cloudy/conf/sunshine/apps.json
@@ -142,6 +142,23 @@
"wait-all": "true",
"exit-timeout": "5",
"cmd": ""
+ },
+ {
+ "name": "MoonDeckStream",
+ "prep-cmd": [
+ {
+ "do": "sh -c \"sunshine-app-startup.sh > \/tmp\/sunshine-session-start.log 2>&1\"",
+ "undo": "sh -c \"moondeckstream-stop.sh > \/tmp\/moondeckstream-stop.log 2>&1\""
+ }
+ ],
+ "detached": [
+ "MOONDECKBUDDY_EXEC_STREAM=1 sh -c \"moondeckstream-start.sh > \/tmp\/moondeckstream-start.log 2>&1\""
+ ],
+ "exclude-global-prep-cmd": "false",
+ "auto-detach": "true",
+ "wait-all": "true",
+ "exit-timeout": "5",
+ "cmd": ""
}
]
}
\ No newline at end of file
diff --git a/containers/sunshine/overlay/cloudy/conf/supervisor/supervisord.conf b/containers/sunshine/overlay/cloudy/conf/supervisor/supervisord.conf
index a6b2d38b..c44c095c 100644
--- a/containers/sunshine/overlay/cloudy/conf/supervisor/supervisord.conf
+++ b/containers/sunshine/overlay/cloudy/conf/supervisor/supervisord.conf
@@ -70,6 +70,21 @@ stopsignal=TERM
stdout_logfile=%(ENV_CLOUDYPAD_LOG_DIR)s/sunshine.log
stderr_logfile=%(ENV_CLOUDYPAD_LOG_DIR)s/sunshine.err.log
+[program:moondeckbuddy]
+priority=50
+autostart=true
+autorestart=true
+user=%(ENV_CLOUDYPAD_USER)s
+command=/cloudy/bin/start-moondeckbuddy.sh
+environment=
+ HOME="%(ENV_CLOUDYPAD_USER_HOME)s",
+ USER="%(ENV_CLOUDYPAD_USER)s",
+ DISPLAY="%(ENV_DISPLAY)s",
+ XDG_RUNTIME_DIR="%(ENV_XDG_RUNTIME_DIR)s"
+stopsignal=TERM
+stdout_logfile=%(ENV_CLOUDYPAD_LOG_DIR)s/moondeckbuddy.log
+stderr_logfile=%(ENV_CLOUDYPAD_LOG_DIR)s/moondeckbuddy.err.log
+
[program:pulseaudio]
priority=20
autostart=true
diff --git a/containers/sunshine/overlay/cloudy/conf/xfce4-default/xfconf/xfce-perchannel-xml/xfce4-panel.xml b/containers/sunshine/overlay/cloudy/conf/xfce4-default/xfconf/xfce-perchannel-xml/xfce4-panel.xml
index 47d64ce2..5e68f480 100644
--- a/containers/sunshine/overlay/cloudy/conf/xfce4-default/xfconf/xfce-perchannel-xml/xfce4-panel.xml
+++ b/containers/sunshine/overlay/cloudy/conf/xfce4-default/xfconf/xfce-perchannel-xml/xfce4-panel.xml
@@ -17,6 +17,7 @@
+
@@ -76,6 +77,8 @@
+
+
diff --git a/src/core/const.ts b/src/core/const.ts
index 599daf0d..220ff8f2 100644
--- a/src/core/const.ts
+++ b/src/core/const.ts
@@ -116,6 +116,7 @@ export const CLOUDYPAD_SUNSHINE_PORTS: SimplePortDefinition[] = [
{ port: 47989, protocol: 'tcp' }, // HTTP
{ port: 47990, protocol: 'tcp' }, // Web
{ port: 48010, protocol: 'tcp' }, // RTSP
+ { port: 59999, protocol: "tcp" }, // MoonDeckBuddy
{ port: 47998, protocol: 'udp' }, // Video
{ port: 47999, protocol: 'udp' }, // Control