From c8c6397192d89e98b54ecf16cd852818725d9671 Mon Sep 17 00:00:00 2001 From: Andrew Zambazos Date: Wed, 21 Jan 2026 11:26:26 +1300 Subject: [PATCH] Update linux sh files and appdir folder --- appdir-example/Nebula | 185 ++++++++++++++++++ appdir-example/nebula.desktop | 10 + appdir-example/run-nebula.sh | 24 +++ appdir-example/steam_appid.txt | 1 + .../usr/share/applications/nebula.desktop | 9 + make-appdir.sh | 32 ++- update-appdir.sh | 38 +++- 7 files changed, 294 insertions(+), 5 deletions(-) create mode 100755 appdir-example/Nebula create mode 100755 appdir-example/nebula.desktop create mode 100755 appdir-example/run-nebula.sh create mode 100644 appdir-example/steam_appid.txt create mode 100644 appdir-example/usr/share/applications/nebula.desktop mode change 100644 => 100755 make-appdir.sh diff --git a/appdir-example/Nebula b/appdir-example/Nebula new file mode 100755 index 0000000..b4fc8ec --- /dev/null +++ b/appdir-example/Nebula @@ -0,0 +1,185 @@ +#!/usr/bin/env bash +# Run Nebula from an extracted AppImage folder with safe LD/XDG paths and Linux flags. +# This repo can end up with either: +# - nebula-appdir/squashfs-root/nebula (common after copying squashfs-root into nebula-appdir) +# - nebula-appdir/nebula (if you copied the extracted contents directly into nebula-appdir) +# +# PORTABLE MODE: User data (cookies, history, bookmarks) is stored in usr/data/ alongside the app. +# This keeps all data self-contained and portable on Linux. +set -euo pipefail + +SELF_DIR="$(cd "$(dirname "$0")" >/dev/null 2>&1 && pwd)" + +if [ -x "$SELF_DIR/nebula-appdir/nebula" ]; then + APPROOT="$SELF_DIR/nebula-appdir" + BIN="$APPROOT/nebula" +elif [ -x "$SELF_DIR/squashfs-root/nebula" ]; then + APPROOT="$SELF_DIR/squashfs-root" + BIN="$APPROOT/nebula" +elif [ -x "$SELF_DIR/nebula" ]; then + APPROOT="$SELF_DIR" + BIN="$APPROOT/nebula" +else + echo "Nebula binary not found. Expected either:" + echo "- $SELF_DIR/nebula-appdir/nebula" + echo "- $SELF_DIR/squashfs-root/nebula" + echo "- $SELF_DIR/nebula" + exit 1 +fi + +# --- PORTABLE DATA CONFIGURATION --- +# Store user data (cookies, history, bookmarks, etc.) in a local folder +# Data is stored with secure permissions (700 for dirs, 600 for files) +PORTABLE_DATA_DIR="$SELF_DIR/usr/data" +export NEBULA_PORTABLE=1 +export NEBULA_PORTABLE_PATH="$PORTABLE_DATA_DIR" + +# Create portable data directory with secure permissions if it doesn't exist +if [ ! -d "$PORTABLE_DATA_DIR" ]; then + mkdir -p "$PORTABLE_DATA_DIR" + chmod 700 "$PORTABLE_DATA_DIR" +fi + +export LD_LIBRARY_PATH="$APPROOT/usr/lib:${LD_LIBRARY_PATH:-}" +export XDG_DATA_DIRS="$APPROOT/usr/share:${XDG_DATA_DIRS:-/usr/share}" + +# ============================================================================= +# STEAM INPUT CONFIGURATION - Always set these to prevent controller emulation +# ============================================================================= +# These variables tell Steam's input layer that this app handles controller +# input natively and should NOT have mouse/keyboard emulation applied. +# Set unconditionally since Software apps may not receive Steam env vars. + +# Disable Steam's virtual gamepad layer - CRITICAL for native controller support +export SDL_GAMECONTROLLER_ALLOW_STEAM_VIRTUAL_GAMEPAD=0 +export STEAM_INPUT_ENABLE_VIRTUAL_GAMEPAD=0 + +# Allow raw gamepad access +export SDL_GAMECONTROLLER_IGNORE_DEVICES="" + +# Allow background gamepad events (useful when app doesn't have focus) +export SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS=1 + +# Hint to SDL that we're using gamepads natively +export SDL_GAMECONTROLLERCONFIG="${SDL_GAMECONTROLLERCONFIG:-}" + +# Steam can inject its overlay via LD_PRELOAD (gameoverlayrenderer.so). +# In some setups this breaks Chromium/Electron gamepad input. When we detect +# a Steam-launched session, strip the overlay preload but keep other entries. +# Also configure additional Steam-specific settings. +if [ -n "${SteamAppId:-}" ] || [ -n "${STEAM_APP_ID:-}" ] || [ -n "${STEAM_COMPAT_CLIENT_INSTALL_PATH:-}" ] || [ -n "${STEAM_COMPAT_DATA_PATH:-}" ]; then + # Enable Big Picture Mode for controller-friendly UI when launched from Steam + export NEBULA_BIG_PICTURE="${NEBULA_BIG_PICTURE:-1}" + + # Enable GPU acceleration on Linux + export NEBULA_GPU_ALLOW_LINUX=1 + + if [ -n "${LD_PRELOAD:-}" ]; then + CLEANED_LD_PRELOAD="" + IFS=':' read -r -a _preload_parts <<< "$LD_PRELOAD" + for _p in "${_preload_parts[@]}"; do + [ -z "$_p" ] && continue + case "$_p" in + *gameoverlayrenderer.so*) + ;; + *) + if [ -z "$CLEANED_LD_PRELOAD" ]; then + CLEANED_LD_PRELOAD="$_p" + else + CLEANED_LD_PRELOAD="$CLEANED_LD_PRELOAD:$_p" + fi + ;; + esac + done + if [ -z "$CLEANED_LD_PRELOAD" ]; then + unset LD_PRELOAD + else + export LD_PRELOAD="$CLEANED_LD_PRELOAD" + fi + fi +fi + +GPU_ARGS=() + +# Optional GPU tuning profiles strike a balance between enabling hardware decode +# and keeping the launcher safe on systems with fragile Mesa/VA-API stacks. +# Default to enabling GPU tweaks on Linux unless explicitly disabled. +export NEBULA_GPU_PROFILE="${NEBULA_GPU_PROFILE:-}" +GPU_GL_MODE="${NEBULA_GPU_GL:-}" +export NEBULA_GPU_TWEAKS="${NEBULA_GPU_TWEAKS:-1}" + +if [ "${NEBULA_GPU_TWEAKS}" = "1" ] && [ -z "$NEBULA_GPU_PROFILE" ]; then + export NEBULA_GPU_PROFILE=vaapi +fi + +case "$NEBULA_GPU_PROFILE" in + vaapi) + GPU_ARGS+=(--ignore-gpu-blocklist) + GPU_ARGS+=(--enable-features=VaapiVideoDecoder,VaapiVideoEncoder,CanvasOopRasterization,UseSkiaRenderer,VaapiVideoDecoderLinuxGL,VaapiVideoDecoderLinuxZeroCopyGL) + GPU_ARGS+=(--enable-zero-copy) + GPU_ARGS+=(--enable-gpu-rasterization) + GPU_ARGS+=(--enable-accelerated-video-decode) + GPU_ARGS+=(--enable-native-gpu-memory-buffers) + if [ -z "${LIBVA_DRIVER_NAME:-}" ]; then + export LIBVA_DRIVER_NAME=radeonsi + fi + ;; + angle) + GPU_ARGS+=(--ignore-gpu-blocklist) + GPU_ARGS+=(--enable-features=VaapiVideoDecoder,VaapiVideoEncoder,CanvasOopRasterization,UseSkiaRenderer,VaapiVideoDecoderLinuxGL) + GPU_ARGS+=(--enable-zero-copy) + GPU_ARGS+=(--enable-gpu-rasterization) + GPU_ARGS+=(--enable-native-gpu-memory-buffers) + GPU_ARGS+=(--enable-accelerated-video-decode) + if [ -z "${LIBVA_DRIVER_NAME:-}" ]; then + export LIBVA_DRIVER_NAME=radeonsi + fi + if [ -z "${AMD_VULKAN_ICD:-}" ]; then + export AMD_VULKAN_ICD=RADV + fi + ;; + amd-handheld) + GPU_ARGS+=(--ignore-gpu-blocklist) + GPU_ARGS+=(--use-angle=vulkan) + AMD_HANDHELD_FEATURES="VaapiVideoDecoder,VaapiVideoEncoder,CanvasOopRasterization,UseSkiaRenderer,VaapiVideoDecoderLinuxGL,VaapiVideoDecoderLinuxZeroCopyGL" + if [ -n "${WAYLAND_DISPLAY:-}" ] || [ "${XDG_SESSION_TYPE:-}" = "wayland" ]; then + AMD_HANDHELD_FEATURES="UseOzonePlatform,WaylandWindowDecorations,${AMD_HANDHELD_FEATURES}" + GPU_ARGS+=(--ozone-platform-hint=auto) + GPU_ARGS+=(--ozone-platform=wayland) + fi + GPU_ARGS+=(--enable-features="$AMD_HANDHELD_FEATURES") + GPU_ARGS+=(--enable-zero-copy) + GPU_ARGS+=(--enable-gpu-rasterization) + if [ -z "${LIBVA_DRIVER_NAME:-}" ]; then + export LIBVA_DRIVER_NAME=radeonsi + fi + if [ -z "${MESA_VK_WSI_PRESENT_MODE:-}" ]; then + export MESA_VK_WSI_PRESENT_MODE=mailbox + fi + ;; + software) + GPU_ARGS+=(--disable-gpu) + ;; + "") + ;; + *) + echo "Warning: Unknown NEBULA_GPU_PROFILE '$NEBULA_GPU_PROFILE'" >&2 + ;; +esac + +if [ -n "$GPU_GL_MODE" ]; then + # Map common GL mode names to Electron-compatible values + case "$GPU_GL_MODE" in + egl|egl-angle) GPU_GL_MODE="angle" ;; + desktop) GPU_GL_MODE="desktop" ;; + esac + GPU_ARGS+=(--use-gl="$GPU_GL_MODE") +fi + +if [ -n "${NEBULA_GPU_EXTRA_ARGS:-}" ]; then + # shellcheck disable=SC2086 # word splitting is intentional for custom flag tokens + read -r -a _nebula_gpu_extra <<< "${NEBULA_GPU_EXTRA_ARGS}" + GPU_ARGS+=("${_nebula_gpu_extra[@]}") +fi + +exec "$BIN" --no-sandbox "${GPU_ARGS[@]}" "$@" diff --git a/appdir-example/nebula.desktop b/appdir-example/nebula.desktop new file mode 100755 index 0000000..6c57a27 --- /dev/null +++ b/appdir-example/nebula.desktop @@ -0,0 +1,10 @@ +#!/usr/bin/env xdg-open +[Desktop Entry] +Name=Nebula +Comment=Nebula Browser (Portable Mode - data stored locally) +Exec=env NEBULA_GPU_TWEAKS=1 /home/deck/Documents/Repos/NebulaBrowser/nebula-appdir/Nebula %U +Terminal=false +Type=Application +Icon=nebula +Categories=Network;WebBrowser; +StartupWMClass=Nebula diff --git a/appdir-example/run-nebula.sh b/appdir-example/run-nebula.sh new file mode 100755 index 0000000..82568df --- /dev/null +++ b/appdir-example/run-nebula.sh @@ -0,0 +1,24 @@ +#!/bin/bash +# Run Nebula with portable data storage +# User data (cookies, history, bookmarks) is stored in usr/data/ alongside the app. +set -e + +HERE="$(cd "$(dirname "$0")" && pwd)" + +export APPDIR="$HERE" +export PATH="$HERE/usr/bin:$PATH" +export LD_LIBRARY_PATH="$HERE/usr/lib:$HERE/usr/lib64:$LD_LIBRARY_PATH" + +# --- PORTABLE DATA CONFIGURATION --- +# Store user data in a local folder for portable operation +PORTABLE_DATA_DIR="$HERE/usr/data" +export NEBULA_PORTABLE=1 +export NEBULA_PORTABLE_PATH="$PORTABLE_DATA_DIR" + +# Create portable data directory with secure permissions if it doesn't exist +if [ ! -d "$PORTABLE_DATA_DIR" ]; then + mkdir -p "$PORTABLE_DATA_DIR" + chmod 700 "$PORTABLE_DATA_DIR" +fi + +exec "$HERE/nebula-appdir/AppRun" diff --git a/appdir-example/steam_appid.txt b/appdir-example/steam_appid.txt new file mode 100644 index 0000000..557197f --- /dev/null +++ b/appdir-example/steam_appid.txt @@ -0,0 +1 @@ +4290110 diff --git a/appdir-example/usr/share/applications/nebula.desktop b/appdir-example/usr/share/applications/nebula.desktop new file mode 100644 index 0000000..c4c2a63 --- /dev/null +++ b/appdir-example/usr/share/applications/nebula.desktop @@ -0,0 +1,9 @@ +[Desktop Entry] +Name=Nebula +Comment=Nebula Browser +Exec=./Nebula %U +Terminal=false +Type=Application +Icon=nebula +Categories=Network;WebBrowser; +StartupWMClass=Nebula diff --git a/make-appdir.sh b/make-appdir.sh old mode 100644 new mode 100755 index 2df8982..b9d1617 --- a/make-appdir.sh +++ b/make-appdir.sh @@ -3,6 +3,7 @@ set -euo pipefail SRC="${1:-squashfs-root}" DEST="${2:-nebula-appdir}" +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" if [ ! -d "$SRC" ]; then echo "Source $SRC not found. Extract the AppImage first (./dist/Nebula-*.AppImage --appimage-extract)" @@ -52,8 +53,37 @@ StartupWMClass=Nebula EOF fi +# Match appdir-example layout: extract app.asar to resources/app and keep app.asar.orig +if [ -f "$DEST/resources/app.asar" ]; then + if command -v npx &> /dev/null; then + echo "Extracting app.asar to resources/app (keeping app.asar.orig)" + (cd "$DEST/resources" && npx asar extract "app.asar" "app") + mv "$DEST/resources/app.asar" "$DEST/resources/app.asar.orig" 2>/dev/null || true + else + echo "Warning: npx not found; leaving app.asar in place." + fi +fi + +# Copy Linux launch wrappers if present in appdir-example +if [ -f "$SCRIPT_DIR/appdir-example/run-nebula.sh" ]; then + cp "$SCRIPT_DIR/appdir-example/run-nebula.sh" "$DEST/run-nebula.sh" + chmod +x "$DEST/run-nebula.sh" || true +fi +if [ -f "$SCRIPT_DIR/appdir-example/steam_appid.txt" ]; then + cp "$SCRIPT_DIR/appdir-example/steam_appid.txt" "$DEST/steam_appid.txt" +fi +if [ -f "$SCRIPT_DIR/appdir-example/nebula.desktop" ]; then + cp "$SCRIPT_DIR/appdir-example/nebula.desktop" "$DEST/nebula.desktop" + cp "$SCRIPT_DIR/appdir-example/nebula.desktop" "$DEST/usr/share/applications/nebula.desktop" +fi +# Ensure root launcher exists (from example if needed) +if [ -f "$SCRIPT_DIR/appdir-example/Nebula" ]; then + cp "$SCRIPT_DIR/appdir-example/Nebula" "$DEST/Nebula" + chmod +x "$DEST/Nebula" || true +fi + # Fix permissions chmod -R a+r "$DEST/usr/share/icons/hicolor/256x256/apps" || true chmod +x "$DEST/Nebula" || true -echo "AppDir assembled at $DEST. Run with: $DEST/Nebula" \ No newline at end of file +echo "AppDir assembled at $DEST. Run with: $DEST/run-nebula.sh" \ No newline at end of file diff --git a/update-appdir.sh b/update-appdir.sh index ad8e053..6e9e34b 100755 --- a/update-appdir.sh +++ b/update-appdir.sh @@ -5,17 +5,46 @@ set -e SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" -APP_DIR="$SCRIPT_DIR/nebula-appdir/nebula-appdir/resources/app" +APPDIR_ROOT="$SCRIPT_DIR/nebula-appdir" +# Support both layouts: +# 1) nebula-appdir/resources/app +# 2) nebula-appdir/nebula-appdir/resources/app (example layout) +if [ -d "$APPDIR_ROOT/resources" ] || [ -f "$APPDIR_ROOT/resources/app.asar" ]; then + RESOURCES_DIR="$APPDIR_ROOT/resources" +else + RESOURCES_DIR="$APPDIR_ROOT/nebula-appdir/resources" +fi +APP_DIR="$RESOURCES_DIR/app" +ASAR_FILE="$RESOURCES_DIR/app.asar" +ASAR_ORIG_FILE="$RESOURCES_DIR/app.asar.orig" echo "🚀 Updating Nebula AppDir..." echo " Source: $SCRIPT_DIR" echo " Target: $APP_DIR" echo "" -# Check if target exists +# Check if target exists (or extract from app.asar if present) if [ ! -d "$APP_DIR" ]; then - echo "❌ Error: AppDir not found at $APP_DIR" - exit 1 + if [ -f "$ASAR_FILE" ] || [ -f "$ASAR_ORIG_FILE" ]; then + if command -v npx &> /dev/null; then + if [ -f "$ASAR_FILE" ]; then + echo "â„šī¸ app.asar detected. Extracting to $APP_DIR..." + (cd "$RESOURCES_DIR" && npx asar extract "app.asar" "app") + mv "$ASAR_FILE" "$ASAR_ORIG_FILE" 2>/dev/null || true + else + echo "â„šī¸ app.asar.orig detected. Extracting to $APP_DIR..." + (cd "$RESOURCES_DIR" && npx asar extract "app.asar.orig" "app") + fi + else + echo "❌ Error: $APP_DIR not found and npx is not available to extract app.asar." + echo " Install Node.js/npm, then run:" + echo " cd $RESOURCES_DIR && npx asar extract app.asar app" + exit 1 + fi + else + echo "❌ Error: AppDir not found at $APP_DIR" + exit 1 + fi fi # Files to sync (main app files) @@ -23,6 +52,7 @@ FILES=( "main.js" "preload.js" "package.json" + "portable-data.js" "gpu-config.js" "gpu-fallback.js" "performance-monitor.js"