diff --git a/.gitignore b/.gitignore index 680c727d..853abcf7 100644 --- a/.gitignore +++ b/.gitignore @@ -10,4 +10,5 @@ test/unit/core/state/TMP-v0-root-data-dir .vagrant **/__pycache__ **/.venv -test/integ/.data-root-dir \ No newline at end of file +test/integ/.data-root-dir +ansible/inventories/custom-dev.yml diff --git a/containers/sunshine/Dockerfile b/containers/sunshine/Dockerfile index 6987f523..103fec44 100644 --- a/containers/sunshine/Dockerfile +++ b/containers/sunshine/Dockerfile @@ -84,6 +84,7 @@ apt install -y \ xterm \ xz-utils \ zenity \ + jq \ bubblewrap \ software-properties-common \ nano \ @@ -283,6 +284,9 @@ HEALTHCHECK --interval=10s --timeout=5s --start-period=5s --retries=3 \ # Allow user "cloudy" to stop container RUN echo "cloudy ALL=(ALL) NOPASSWD: ${CLOUDYPAD_BIN_DIR}/stop-supervisord.sh" > /etc/sudoers.d/cloudy-stop-container +# Allow user "cloudy" to install apps without password (for App Installer) +RUN echo "cloudy ALL=(ALL) NOPASSWD: /usr/bin/apt-get, /usr/bin/apt, /usr/bin/install, /usr/bin/ln, /usr/bin/mkdir" > /etc/sudoers.d/cloudy-app-install + # Contain various Cloudy Pad scripts, add to PATH for easier use ENV PATH=$PATH:/cloudy/bin diff --git a/containers/sunshine/overlay/cloudy/bin/cloudy-app-installer.sh b/containers/sunshine/overlay/cloudy/bin/cloudy-app-installer.sh new file mode 100755 index 00000000..ea80f9ab --- /dev/null +++ b/containers/sunshine/overlay/cloudy/bin/cloudy-app-installer.sh @@ -0,0 +1,95 @@ +#!/usr/bin/env bash + +# +# Cloudy Pad App Installer +# Install optional applications on-demand +# + +INSTALL_SCRIPTS_DIR="/cloudy/bin" + +show_menu() { + zenity --list \ + --title="Cloudy Pad App Installer" \ + --text="Select an application to install:" \ + --column="App" --column="Description" --column="Status" \ + --width=500 --height=400 \ + --ok-label="Install" \ + --cancel-label="Close" \ + "Prism Launcher" "Minecraft launcher" "$(get_status prismlauncher)" +} + +get_status() { + case "$1" in + prismlauncher) + if [ -x "/opt/prismlauncher/PrismLauncher.AppImage" ]; then + echo "Installed" + else + echo "Not installed" + fi + ;; + esac +} + +install_app() { + case "$1" in + "Prism Launcher") + install_prismlauncher + ;; + esac +} + +install_prismlauncher() { + if [ -x "/opt/prismlauncher/PrismLauncher.AppImage" ]; then + zenity --question \ + --title="Prism Launcher" \ + --text="Prism Launcher is already installed.\n\nDo you want to launch it?" \ + --ok-label="Launch" \ + --cancel-label="Back" + if [ $? -eq 0 ]; then + prismlauncher-start.sh & + exit 0 + fi + else + "${INSTALL_SCRIPTS_DIR}/install-prismlauncher.sh" | zenity --progress \ + --title="Installing Prism Launcher" \ + --text="Starting installation..." \ + --percentage=0 \ + --auto-close \ + --width=400 + + if [ -x "/opt/prismlauncher/PrismLauncher.AppImage" ]; then + choice=$(zenity --list \ + --title="Installation Complete" \ + --text="Prism Launcher installed successfully!" \ + --column="Action" --column="Description" \ + --width=500 --height=300 \ + "Launch now" "Start Prism Launcher" \ + "Show in Moonlight" "Restart session to update Moonlight app list" \ + "Close" "Continue using desktop") + + case "$choice" in + "Launch now") + prismlauncher-start.sh & + ;; + "Show in Moonlight") + pkill -TERM sunshine + ;; + esac + exit 0 + else + zenity --error \ + --title="Installation Failed" \ + --text="Installation failed.\n\nCheck /tmp/prismlauncher-install.log for details." + fi + fi +} + +while true; do + choice=$(show_menu) + + if [ -z "$choice" ]; then + exit 0 + fi + + install_app "$choice" +done diff --git a/containers/sunshine/overlay/cloudy/bin/install-prismlauncher.sh b/containers/sunshine/overlay/cloudy/bin/install-prismlauncher.sh new file mode 100755 index 00000000..05ee20bf --- /dev/null +++ b/containers/sunshine/overlay/cloudy/bin/install-prismlauncher.sh @@ -0,0 +1,67 @@ +#!/usr/bin/env bash + +# +# Installation script for Prism Launcher (Minecraft) +# + +set -e + +PRISMLAUNCHER_VERSION="${PRISMLAUNCHER_VERSION:-10.0.2}" +PRISMLAUNCHER_APP_DIR="/opt/prismlauncher" +PRISMLAUNCHER_APPIMAGE_URL="https://github.com/PrismLauncher/PrismLauncher/releases/download/${PRISMLAUNCHER_VERSION}/PrismLauncher-Linux-x86_64.AppImage" + +is_installed() { + [ -x "${PRISMLAUNCHER_APP_DIR}/PrismLauncher.AppImage" ] +} + +add_to_sunshine_apps() { + APPS_JSON="${XDG_CONFIG_HOME}/sunshine/apps.json" + + [ ! -f "$APPS_JSON" ] && return + + # Check if already added + if jq -e '.apps[] | select(.name | contains("Prism Launcher"))' "$APPS_JSON" > /dev/null 2>&1; then + return + fi + + # Add new app + jq '.apps += [{ + "name": "Prism Launcher (Minecraft)", + "image-path": "$(XDG_CONFIG_HOME)/sunshine/assets/prismlauncher.png", + "prep-cmd": [{ + "do": "sh -c \"sunshine-app-startup.sh > /tmp/sunshine-session-start.log 2>&1\"", + "undo": "sh -c \"prismlauncher-stop.sh > /tmp/prismlauncher-stop.log 2>&1\"" + }], + "detached": ["sh -c \"prismlauncher-start.sh > /tmp/prismlauncher-start.log 2>&1\""], + "exclude-global-prep-cmd": "false", + "auto-detach": "true", + "wait-all": "true", + "exit-timeout": "5", + "cmd": "" + }]' "$APPS_JSON" > "${APPS_JSON}.tmp" && mv "${APPS_JSON}.tmp" "$APPS_JSON" +} + +if is_installed; then + echo "Already installed" + exit 0 +fi + +echo "10"; echo "# Installing dependencies..." +sudo apt-get update > /tmp/prismlauncher-install.log 2>&1 + +echo "30"; echo "# Installing Java and fuse..." +sudo apt-get install -y fuse3 libfuse2t64 openjdk-21-jre >> /tmp/prismlauncher-install.log 2>&1 + +echo "50"; echo "# Downloading Prism Launcher..." +curl -L -o /tmp/PrismLauncher.AppImage "${PRISMLAUNCHER_APPIMAGE_URL}" >> /tmp/prismlauncher-install.log 2>&1 + +echo "70"; echo "# Installing Prism Launcher..." +sudo install -d -o "${CLOUDYPAD_USER}" -g "${CLOUDYPAD_USER}" "${PRISMLAUNCHER_APP_DIR}" +sudo install -m 0755 -o "${CLOUDYPAD_USER}" -g "${CLOUDYPAD_USER}" /tmp/PrismLauncher.AppImage "${PRISMLAUNCHER_APP_DIR}/PrismLauncher.AppImage" +sudo ln -sf "${PRISMLAUNCHER_APP_DIR}/PrismLauncher.AppImage" /usr/local/bin/prismlauncher +rm -f /tmp/PrismLauncher.AppImage + +echo "90"; echo "# Adding to Sunshine apps..." +add_to_sunshine_apps + +echo "100"; echo "# Done!" diff --git a/containers/sunshine/overlay/cloudy/bin/prismlauncher-start.sh b/containers/sunshine/overlay/cloudy/bin/prismlauncher-start.sh new file mode 100755 index 00000000..39161791 --- /dev/null +++ b/containers/sunshine/overlay/cloudy/bin/prismlauncher-start.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash + +wait-x-availability.sh + +PRISMLAUNCHER_APPIMAGE_PATH="/opt/prismlauncher/PrismLauncher.AppImage" + +if [ ! -x "$PRISMLAUNCHER_APPIMAGE_PATH" ]; then + echo "Prism Launcher is not installed." + echo "Run 'install-prismlauncher.sh' to install it." + zenity --error --text="Prism Launcher is not installed.\n\nOpen a terminal and run:\ninstall-prismlauncher.sh" --title="Prism Launcher" 2>/dev/null || true + exit 1 +fi + +cd "$CLOUDYPAD_USER_HOME" + +"$PRISMLAUNCHER_APPIMAGE_PATH" & + +PRISMLAUNCHER_PID=$! +echo $PRISMLAUNCHER_PID > /tmp/prismlauncher.pid +echo "Prism Launcher started with PID: $PRISMLAUNCHER_PID" + +wait $PRISMLAUNCHER_PID diff --git a/containers/sunshine/overlay/cloudy/bin/prismlauncher-stop.sh b/containers/sunshine/overlay/cloudy/bin/prismlauncher-stop.sh new file mode 100755 index 00000000..ee26f97c --- /dev/null +++ b/containers/sunshine/overlay/cloudy/bin/prismlauncher-stop.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash + +echo "Stopping Prism Launcher..." + +if [ ! -f /tmp/prismlauncher.pid ]; then + echo "No Prism Launcher PID found at /tmp/prismlauncher.pid... Not stopping." + exit 0 +fi + +PRISMLAUNCHER_PID=$(cat /tmp/prismlauncher.pid) + +echo "Killing Prism Launcher with PID: $PRISMLAUNCHER_PID" + +kill $PRISMLAUNCHER_PID + +echo "Prism Launcher stopped" diff --git a/containers/sunshine/overlay/cloudy/bin/setup-dirs.sh b/containers/sunshine/overlay/cloudy/bin/setup-dirs.sh index dfb6ea0c..45949438 100755 --- a/containers/sunshine/overlay/cloudy/bin/setup-dirs.sh +++ b/containers/sunshine/overlay/cloudy/bin/setup-dirs.sh @@ -19,7 +19,8 @@ mkdir -p \ $XDG_CACHE_HOME \ $XDG_CONFIG_HOME \ $XDG_DATA_HOME \ - $CLOUDYPAD_USER_HOME + $CLOUDYPAD_USER_HOME \ + $CLOUDYPAD_USER_HOME/Desktop chown $CLOUDYPAD_USER:$CLOUDYPAD_USER \ $CLOUDYPAD_DATA_DIR \ @@ -38,3 +39,10 @@ chmod 0700 \ $XDG_CONFIG_HOME \ $XDG_DATA_HOME \ $CLOUDYPAD_USER_HOME + +# Copy desktop shortcuts to user's Desktop +if [ -d "/cloudy/conf/desktop-shortcuts" ]; then + cp /cloudy/conf/desktop-shortcuts/*.desktop $CLOUDYPAD_USER_HOME/Desktop/ 2>/dev/null || true + chown -R $CLOUDYPAD_USER:$CLOUDYPAD_USER $CLOUDYPAD_USER_HOME/Desktop + chmod 755 $CLOUDYPAD_USER_HOME/Desktop/*.desktop 2>/dev/null || true +fi diff --git a/containers/sunshine/overlay/cloudy/conf/desktop-shortcuts/app-installer.desktop b/containers/sunshine/overlay/cloudy/conf/desktop-shortcuts/app-installer.desktop new file mode 100644 index 00000000..c0474338 --- /dev/null +++ b/containers/sunshine/overlay/cloudy/conf/desktop-shortcuts/app-installer.desktop @@ -0,0 +1,9 @@ +[Desktop Entry] +Version=1.0 +Type=Application +Name=App Installer +Comment=Install optional applications +Exec=/cloudy/bin/cloudy-app-installer.sh +Icon=gnome-app-install +Terminal=false +Categories=System; diff --git a/containers/sunshine/overlay/cloudy/conf/sunshine/apps.json b/containers/sunshine/overlay/cloudy/conf/sunshine/apps.json index b9bc2a92..55fd5ace 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": "App Installer", + "image-path": "$(XDG_CONFIG_HOME)/sunshine/assets/app-installer.png", + "prep-cmd": [ + { + "do": "sh -c \"sunshine-app-startup.sh > \/tmp\/sunshine-session-start.log 2>&1\"" + } + ], + "detached": [ + "sh -c \"cloudy-app-installer.sh > \/tmp\/app-installer.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/sunshine/assets/app-installer.png b/containers/sunshine/overlay/cloudy/conf/sunshine/assets/app-installer.png new file mode 100644 index 00000000..f64fd1d4 Binary files /dev/null and b/containers/sunshine/overlay/cloudy/conf/sunshine/assets/app-installer.png differ diff --git a/containers/sunshine/overlay/cloudy/conf/sunshine/assets/prismlauncher.png b/containers/sunshine/overlay/cloudy/conf/sunshine/assets/prismlauncher.png new file mode 100644 index 00000000..79781e64 Binary files /dev/null and b/containers/sunshine/overlay/cloudy/conf/sunshine/assets/prismlauncher.png differ diff --git a/containers/sunshine/overlay/cloudy/conf/xfce4-default/panel/launcher-18/prismlauncher.desktop b/containers/sunshine/overlay/cloudy/conf/xfce4-default/panel/launcher-18/prismlauncher.desktop new file mode 100644 index 00000000..17f61bb3 --- /dev/null +++ b/containers/sunshine/overlay/cloudy/conf/xfce4-default/panel/launcher-18/prismlauncher.desktop @@ -0,0 +1,13 @@ +[Desktop Entry] +Name=Prism Launcher +Comment=launcher for Minecraft +Exec=prismlauncher-start.sh +Icon=prismlauncher +Terminal=false +Type=Application +Categories=Game; +PrefersNonDefaultGPU=true +X-KDE-RunOnDiscreteGpu=true +X-XFCE-Source=file:///usr/share/applications/prismlauncher.desktop +Path= +StartupNotify=false 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..8d3f964e 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 @@ -45,6 +45,9 @@ + + + @@ -108,6 +111,12 @@ + + + + + +