Skip to content

Instantly share code, notes, and snippets.

@kipavy
Last active November 23, 2025 00:30
Show Gist options
  • Select an option

  • Save kipavy/2e71fd3624c76e4a7d4f256977152973 to your computer and use it in GitHub Desktop.

Select an option

Save kipavy/2e71fd3624c76e4a7d4f256977152973 to your computer and use it in GitHub Desktop.
One-step installer for switch emulators on Linux and Windows

Switch Emulator Installer

One-step installer for Switch emulators on Linux and Windows.

Automatically downloads and installs your chosen emulator along with the latest firmware and decryption keys.

Supported Emulators

  • Citron
  • Eden
  • Ryujinx

Usage

Linux

Install default emulator (Citron):

curl -fsSL https://gist.githubusercontent.com/kipavy/2e71fd3624c76e4a7d4f256977152973/raw/installSwitchEmu.sh | bash

Install different emulator or with options:

curl -fsSL https://gist.githubusercontent.com/kipavy/2e71fd3624c76e4a7d4f256977152973/raw/installSwitchEmu.sh | bash -s -- --emulator ryujinx --keys-version 20.4.0

Windows

  1. Open PowerShell.
  2. Copy and paste the following command:

Install default emulator (Citron):

iwr -useb https://gist.githubusercontent.com/kipavy/2e71fd3624c76e4a7d4f256977152973/raw/installSwitchEmuWin.ps1 | iex

Install with options (download first, then pass arguments):

iwr -useb https://gist.githubusercontent.com/kipavy/2e71fd3624c76e4a7d4f256977152973/raw/installSwitchEmuWin.ps1 -OutFile $env:TEMP\install.ps1; & $env:TEMP\install.ps1 --emulator ryujinx --keys-version 20.4.0

Command-Line Options

All options work identically on both Linux and Windows:

-e, --emulator EMU      # Specify emulator: citron (default), ryujinx, eden
-f, --force             # Force reinstall even if already installed
-s, --skip-keys         # Skip downloading prod.keys and firmware
-d, --dir DIR           # Custom installation directory
-v, --keys-version VER  # Specify firmware version (e.g., 20.4.0) (empty will show available versions)
-h, --help          # Show help message

Examples

Linux Examples

# Set the script URL for convenience
SCRIPT_URL="https://gist.githubusercontent.com/kipavy/2e71fd3624c76e4a7d4f256977152973/raw/installSwitchEmu.sh"

# Install Eden
curl -fsSL $SCRIPT_URL | bash -s -- --emulator eden

# Install Ryujinx with custom directory
curl -fsSL $SCRIPT_URL | bash -s -- --emulator ryujinx --dir /opt/ryujinx

# Install Citron without keys/firmware
curl -fsSL $SCRIPT_URL | bash -s -- --skip-keys

# Force reinstall Eden with specific firmware version
curl -fsSL $SCRIPT_URL | bash -s -- --emulator eden --force --keys-version 20.4.0

Windows Examples

# Set the script URL for convenience
$SCRIPT_URL = "https://gist.githubusercontent.com/kipavy/2e71fd3624c76e4a7d4f256977152973/raw/installSwitchEmuWin.ps1"

# Download script first
iwr -useb $SCRIPT_URL -OutFile $env:TEMP\install.ps1

# Install Eden
& $env:TEMP\install.ps1 --emulator eden

# Install Ryujinx with custom directory
& $env:TEMP\install.ps1 --emulator ryujinx --dir "C:\Games\Ryujinx"

# Install Citron without keys/firmware
& $env:TEMP\install.ps1 --skip-keys

# Force reinstall Eden with specific firmware version
& $env:TEMP\install.ps1 --emulator eden --force --keys-version 20.4.0

NOTE

This script highly depends on:

https://github.com/THZoria/NX_Firmware/releases
https://github.com/DeaconBlood/PROD.KEYS

if those latest version arent the exact same, not providing a --keys-version will not work...

#!/bin/bash
# script for auto-install + config Nintendo Switch emulators
# Supported emulators: citron, ryujinx, eden
# how it works:
# 1. download latest emulator release for your operating system (windows or linux supported by this script)
# 2. downloads latest (if not --keys-version specified) prod.keys (decryption keys) and corresponding firmware.zip
# 3. move prod.keys to correct emulator location, unzip firmware and move to correct emulator location
set -e # Exit on any error
# ============================================================================
# CONFIGURATION - Edit these values as needed
# ============================================================================
# Emulator configurations
declare -A EMULATOR_CONFIG
# Citron configuration
EMULATOR_CONFIG[citron_api_url]="https://git.citron-emu.org/api/v4/projects/1/releases"
EMULATOR_CONFIG[citron_api_type]="gitlab"
EMULATOR_CONFIG[citron_releases_url]="https://git.citron-emu.org/citron/emu/-/releases/"
EMULATOR_CONFIG[citron_linux_base]="$HOME/.local/share/citron"
EMULATOR_CONFIG[citron_windows_base]="$APPDATA/citron"
EMULATOR_CONFIG[citron_desktop_name]="Citron"
EMULATOR_CONFIG[citron_desktop_comment]="Nintendo Switch Emulator"
# Ryujinx configuration
EMULATOR_CONFIG[ryujinx_api_url]="https://git.ryujinx.app/api/v4/projects/1/releases"
EMULATOR_CONFIG[ryujinx_api_type]="gitlab"
EMULATOR_CONFIG[ryujinx_releases_url]="https://git.ryujinx.app/ryujinx/release-channel-master/-/releases/"
EMULATOR_CONFIG[ryujinx_linux_base]="$HOME/.local/share/Ryujinx"
EMULATOR_CONFIG[ryujinx_windows_base]="$APPDATA/Ryujinx"
EMULATOR_CONFIG[ryujinx_desktop_name]="Ryujinx"
EMULATOR_CONFIG[ryujinx_desktop_comment]="Nintendo Switch Emulator"
# Eden configuration
EMULATOR_CONFIG[eden_api_url]="https://api.github.com/repos/eden-emulator/Releases/releases/latest"
EMULATOR_CONFIG[eden_api_type]="github"
EMULATOR_CONFIG[eden_releases_url]="https://github.com/eden-emulator/Releases/releases"
EMULATOR_CONFIG[eden_linux_base]="$HOME/.local/share/eden"
EMULATOR_CONFIG[eden_windows_base]="$APPDATA/eden"
EMULATOR_CONFIG[eden_desktop_name]="Eden"
EMULATOR_CONFIG[eden_desktop_comment]="Nintendo Switch Emulator"
# Desktop entry details (Linux only)
DESKTOP_CATEGORIES="Game;Emulator;"
# ============================================================================
# END CONFIGURATION
# ============================================================================
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
# Global variables
EMULATOR="citron" # Default emulator
VERSION=""
FORCE_REINSTALL=false
SKIP_KEYS=false
CUSTOM_DIR=""
LINUX_X64_URL=""
LINUX_ARM64_URL=""
WINDOWS_URL=""
KEYS_VERSION=""
ORIG_PWD="$(pwd)"
INSTALL_DIR=""
API_URL=""
RELEASES_URL=""
API_TYPE=""
print_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
print_success() { echo -e "${GREEN}[SUCCESS]${NC} $1"; }
print_warning() { echo -e "${YELLOW}[WARNING]${NC} $1"; }
print_error() { echo -e "${RED}[ERROR]${NC} $1"; }
# ============================================================================
# EMULATOR-SPECIFIC FUNCTIONS
# ============================================================================
get_emulator_config() {
local key="${EMULATOR}_${1}"
echo "${EMULATOR_CONFIG[$key]}"
}
setup_emulator_vars() {
API_URL=$(get_emulator_config "api_url")
RELEASES_URL=$(get_emulator_config "releases_url")
API_TYPE=$(get_emulator_config "api_type")
if [[ -z "$API_URL" ]]; then
print_error "Unsupported emulator: $EMULATOR"
print_info "Supported emulators: citron, ryujinx, eden"
exit 1
fi
print_info "Selected emulator: $EMULATOR"
}
# ============================================================================
# FIRMWARE AND KEYS FUNCTIONS
# ============================================================================
fetch_firmware_tags() {
local tags_json
if ! tags_json=$(curl -sL "https://api.github.com/repos/THZoria/NX_Firmware/tags"); then
return 1
fi
echo "$tags_json" | grep -oE '"name"[[:space:]]*:[[:space:]]*"[^\"]*"' | cut -d'"' -f4
}
get_firmware_versions() {
print_info "Fetching available firmware/key versions from GitHub..."
local versions
if ! versions=$(fetch_firmware_tags); then
print_warning "Failed to fetch version tags from GitHub API"
return 1
fi
if [[ -z "$versions" ]]; then
print_warning "No versions found in GitHub tags response"
return 1
fi
print_info "Available versions:"
echo "$versions"
print_info "re-run the script with --keys-version <version>"
return 0
}
get_latest_firmware_version() {
local versions latest_version
if ! versions=$(fetch_firmware_tags); then
print_warning "Failed to fetch version tags from GitHub API"
return 1
fi
latest_version=$(echo "$versions" | head -1)
if [[ -z "$latest_version" ]]; then
print_warning "No versions found in GitHub tags response"
return 1
fi
echo "$latest_version"
return 0
}
ensure_keys_version() {
if [[ -z "$KEYS_VERSION" ]]; then
if ! KEYS_VERSION=$(get_latest_firmware_version); then
print_error "Failed to determine firmware version"
exit 1
fi
print_info "Using latest firmware version: $KEYS_VERSION"
else
print_info "Using firmware version: $KEYS_VERSION"
fi
}
usage() {
echo "Usage: $0 [OPTIONS]"
echo "Options:"
echo " -e, --emulator EMU Specify emulator to install (citron, ryujinx, eden). Default: citron"
echo " -f, --force Force reinstall even if emulator is already installed"
echo " -s, --skip-keys Skip downloading prod.keys and firmware"
echo " -d, --dir DIR Specify custom emulator installation directory"
echo " -v, --keys-version VER Specify prod.keys / firmware version (e.g. 20.3.0)."
echo " If omitted the script will use the GitHub 'latest'"
echo " releases for prod.keys and firmware."
echo " -h, --help Show this help message"
echo ""
echo "Examples:"
echo " $0"
echo " $0 -e ryujinx"
echo " $0 --emulator eden --skip-keys"
echo " $0 -e ryujinx -d /opt/ryujinx"
echo ""
echo "Supported emulators: citron, ryujinx, eden"
exit 1
}
while [[ $# -gt 0 ]]; do
case $1 in
-e|--emulator)
EMULATOR="$2"
shift 2
;;
-f|--force)
FORCE_REINSTALL=true
shift
;;
-s|--skip-keys)
SKIP_KEYS=true
shift
;;
-d|--dir)
CUSTOM_DIR="$2"
shift 2
;;
-v|--keys-version)
if [[ -z "$2" || "$2" == -* ]]; then
print_warning "No version provided for --keys-version"
get_firmware_versions || true
exit 1
fi
KEYS_VERSION="$2"
shift 2
;;
-h|--help)
usage
;;
*)
echo "Unknown option: $1"
usage
;;
esac
done
detect_os() {
if [[ "$OSTYPE" == "linux-gnu"* ]]; then
OS="linux"
ARCH=$(uname -m)
case $ARCH in
x86_64) ARCH="x64" ;;
aarch64) ARCH="arm64" ;;
*) print_error "Unsupported architecture: $ARCH"; exit 1 ;;
esac
elif [[ "$OSTYPE" == "msys" || "$OSTYPE" == "cygwin" ]]; then
OS="windows"
ARCH="x64"
else
print_error "Unsupported operating system: $OSTYPE"
exit 1
fi
print_info "Detected OS: $OS, Architecture: $ARCH"
}
set_emu_directory() {
if [[ -n "$CUSTOM_DIR" ]]; then
INSTALL_DIR="$CUSTOM_DIR"
elif [[ "$OS" == "linux" ]]; then
INSTALL_DIR=$(get_emulator_config "linux_base")
elif [[ "$OS" == "windows" ]]; then
INSTALL_DIR=$(get_emulator_config "windows_base")
fi
mkdir -p "$INSTALL_DIR"
INSTALL_DIR="$(cd "$INSTALL_DIR"; pwd)" # to absolute
print_info "$EMULATOR will be installed to: $INSTALL_DIR"
}
check_existing_installation() {
if [[ -d "$INSTALL_DIR" && "$FORCE_REINSTALL" == false ]]; then
if [[ -n "$(ls -A "$INSTALL_DIR" 2>/dev/null)" ]]; then
print_warning "$EMULATOR appears to be already installed at $INSTALL_DIR (directory is not empty)"
print_info "Installation cancelled. Use --force to overwrite."
exit 0
fi
fi
}
get_latest_release_info() {
print_info "Fetching latest $EMULATOR release information..."
local api_response
if ! api_response=$(curl -s "$API_URL"); then
print_error "Failed to fetch releases from API: $API_URL"
exit 1
fi
# Extract tag/version once for all branches
VERSION=$(echo "$api_response" | grep -o '"tag_name"[[:space:]]*:[[:space:]]*"[^\"]*"' | head -1 | cut -d'"' -f4 | sed 's/^v//')
if [[ -z "$VERSION" ]]; then
print_error "Could not extract version from API response"
exit 1
fi
print_info "Found latest version: $VERSION"
if [[ "$API_TYPE" == "github" ]]; then
# Extract download URLs from GitHub assets
LINUX_X64_URL=$(echo "$api_response" | grep -o '"browser_download_url"[[:space:]]*:[[:space:]]*"[^\"]*[Ll]inux[^\"]*amd64[^\"]*\.AppImage[^\"]*"' | head -1 | cut -d'"' -f4)
if [[ -z "$LINUX_X64_URL" ]]; then
LINUX_X64_URL=$(echo "$api_response" | grep -o '"browser_download_url"[[:space:]]*:[[:space:]]*"[^\"]*[Ll]inux[^\"]*x86_64[^\"]*\.AppImage[^\"]*"' | head -1 | cut -d'"' -f4)
fi
LINUX_ARM64_URL=$(echo "$api_response" | grep -o '"browser_download_url"[[:space:]]*:[[:space:]]*"[^\"]*[Ll]inux[^\"]*aarch64[^\"]*\.AppImage[^\"]*"' | head -1 | cut -d'"' -f4)
WINDOWS_URL=$(echo "$api_response" | grep -o '"browser_download_url"[[:space:]]*:[[:space:]]*"[^\"]*[Ww]indows[^\"]*\.zip[^\"]*"' | head -1 | cut -d'"' -f4)
if [[ -z "$LINUX_X64_URL" ]]; then
print_warning "Could not find Linux x64 download URL"
fi
if [[ -z "$LINUX_ARM64_URL" ]]; then
print_warning "Could not find Linux ARM64 download URL"
fi
if [[ -z "$WINDOWS_URL" ]]; then
print_warning "Could not find Windows download URL"
fi
elif [[ "$EMULATOR" == "ryujinx" ]]; then
LINUX_X64_URL="https://git.ryujinx.app/api/v4/projects/1/packages/generic/Ryubing/$VERSION/ryujinx-$VERSION-linux_x64.tar.gz"
LINUX_ARM64_URL="https://git.ryujinx.app/api/v4/projects/1/packages/generic/Ryubing/$VERSION/ryujinx-$VERSION-linux_arm64.tar.gz"
WINDOWS_URL="https://git.ryujinx.app/api/v4/projects/1/packages/generic/Ryubing/$VERSION/ryujinx-$VERSION-win_x64.zip"
print_info "Using predictable download URLs for Ryujinx (version: $VERSION)"
elif [[ "$EMULATOR" == "citron" ]]; then
LINUX_X64_URL=$(echo "$api_response" | grep -o '"url":"[^\"]*x86_64[^\"]*AppImage[^\"]*"' | head -1 | cut -d'"' -f4)
LINUX_ARM64_URL=$(echo "$api_response" | grep -o '"url":"[^\"]*aarch64[^\"]*AppImage[^\"]*"' | head -1 | cut -d'"' -f4)
WINDOWS_URL=$(echo "$api_response" | grep -o '"url":"[^\"]*windows[^\"]*zip[^\"]*"' | head -1 | cut -d'"' -f4)
if [[ -z "$LINUX_X64_URL" ]]; then
print_warning "Could not find Linux x64 download URL"
fi
if [[ -z "$LINUX_ARM64_URL" ]]; then
print_warning "Could not find Linux ARM64 download URL"
fi
if [[ -z "$WINDOWS_URL" ]]; then
print_warning "Could not find Windows download URL"
fi
fi
}
download_emu() {
print_info "Downloading $EMULATOR v$VERSION for $OS-$ARCH..."
if [[ "$OS" == "linux" ]]; then
if [[ "$ARCH" == "x64" ]]; then
if [[ -z "$LINUX_X64_URL" ]]; then
print_error "No Linux x64 download URL available"
exit 1
fi
DOWNLOAD_URL="$LINUX_X64_URL"
if [[ "$EMULATOR" == "citron" || "$EMULATOR" == "eden" ]]; then
FILENAME="$(basename "$LINUX_X64_URL")"
else
FILENAME="$EMULATOR-v$VERSION-linux_x64.tar.gz"
fi
elif [[ "$ARCH" == "arm64" ]]; then
if [[ -z "$LINUX_ARM64_URL" ]]; then
print_error "No Linux ARM64 download URL available"
exit 1
fi
DOWNLOAD_URL="$LINUX_ARM64_URL"
if [[ "$EMULATOR" == "citron" || "$EMULATOR" == "eden" ]]; then
FILENAME="$(basename "$LINUX_ARM64_URL")"
else
FILENAME="$EMULATOR-v$VERSION-linux-arm64.tar.gz"
fi
else
print_error "Unsupported Linux architecture: $ARCH"
exit 1
fi
elif [[ "$OS" == "windows" ]]; then
if [[ -z "$WINDOWS_URL" ]]; then
print_error "No Windows download URL available"
exit 1
fi
DOWNLOAD_URL="$WINDOWS_URL"
if [[ "$EMULATOR" == "citron" ]]; then
FILENAME="Citron-Windows-v$VERSION.zip"
elif [[ "$EMULATOR" == "eden" ]]; then
FILENAME="$(basename "$WINDOWS_URL")"
else
FILENAME="$EMULATOR-v$VERSION-win_x64.zip"
fi
fi
TEMP_DIR=$(mktemp -d)
print_info "Downloading from: $DOWNLOAD_URL"
if ! curl -L -o "$TEMP_DIR/$FILENAME" "$DOWNLOAD_URL"; then
print_error "Failed to download $EMULATOR from $DOWNLOAD_URL"
print_info "Please check $RELEASES_URL for updated download links"
exit 1
fi
print_success "Downloaded $FILENAME"
}
install_emu() {
print_info "Installing $EMULATOR to $INSTALL_DIR..."
local archive_path="$TEMP_DIR/$FILENAME"
if [[ "$FILENAME" == *.AppImage ]]; then
cp "$archive_path" "$INSTALL_DIR/$EMULATOR"
chmod +x "$INSTALL_DIR/$EMULATOR"
print_info "AppImage installed as executable"
elif [[ "$FILENAME" == *.zip ]]; then
unzip -o -q "$archive_path" -d "$INSTALL_DIR"
# Handle Ryujinx special case: rename 'publish' folder
if [[ "$EMULATOR" == "ryujinx" ]]; then
local publish_dir="$INSTALL_DIR/publish"
if [[ -d "$publish_dir" ]]; then
print_info "Renaming 'publish' folder to Ryujinx..."
# Move contents from publish to parent, then remove publish
shopt -s dotglob nullglob
mv "$publish_dir"/* "$INSTALL_DIR"/
rmdir "$publish_dir"
shopt -u dotglob nullglob
fi
else
# Citron/Eden: flatten if single subdirectory
local subdir
subdir=$(find "$INSTALL_DIR" -mindepth 1 -maxdepth 1 -type d | head -n 1)
if [[ -n "$subdir" ]] && [[ $(find "$INSTALL_DIR" -mindepth 1 -maxdepth 1 | wc -l) -eq 1 ]]; then
print_info "Moving contents of $(basename "$subdir") up to $INSTALL_DIR..."
shopt -s dotglob nullglob
mv "$subdir"/* "$INSTALL_DIR"/
rmdir "$subdir"
shopt -u dotglob nullglob
fi
fi
if [[ "$OS" == "linux" && -f "$INSTALL_DIR/$EMULATOR" ]]; then
chmod +x "$INSTALL_DIR/$EMULATOR"
fi
print_info "ZIP archive extracted"
elif [[ "$FILENAME" == *.tar.gz ]]; then
# For Ryujinx tar.gz, extract and handle 'publish' folder
if [[ "$EMULATOR" == "ryujinx" ]]; then
local temp_extract="$TEMP_DIR/extract"
mkdir -p "$temp_extract"
tar -xzf "$archive_path" -C "$temp_extract"
# Check if there's a 'publish' folder
if [[ -d "$temp_extract/publish" ]]; then
print_info "Moving contents from 'publish' folder..."
shopt -s dotglob nullglob
mv "$temp_extract/publish"/* "$INSTALL_DIR"/
shopt -u dotglob nullglob
else
# No publish folder, move everything
shopt -s dotglob nullglob
mv "$temp_extract"/* "$INSTALL_DIR"/
shopt -u dotglob nullglob
fi
else
tar -xzf "$archive_path" -C "$INSTALL_DIR" --strip-components=1
fi
if [[ "$OS" == "linux" && -f "$INSTALL_DIR/$EMULATOR" ]]; then
chmod +x "$INSTALL_DIR/$EMULATOR"
fi
print_info "Tar archive extracted"
else
print_error "Unsupported file format: $FILENAME"
exit 1
fi
print_success "$EMULATOR installed successfully"
}
download_keys() {
if [[ "$SKIP_KEYS" == true ]]; then
print_info "Skipping prod.keys download"
return
fi
print_info "Preparing to download prod.keys..."
ensure_keys_version
# Determine keys directory based on emulator
if [[ "$EMULATOR" == "citron" || "$EMULATOR" == "eden" ]]; then
if [[ "$OS" == "linux" ]]; then
KEYS_DIR=$(get_emulator_config "linux_base")"/keys"
else
KEYS_DIR="$INSTALL_DIR/user/keys"
fi
elif [[ "$EMULATOR" == "ryujinx" ]]; then
if [[ "$OS" == "linux" ]]; then
KEYS_DIR="$HOME/.config/Ryujinx/system"
else
KEYS_DIR="$INSTALL_DIR/system"
fi
fi
mkdir -p "$KEYS_DIR"
if [[ -z "$PROD_KEYS_URL" ]]; then
PROD_KEYS_URL="https://github.com/DeaconBlood/PROD.KEYS/releases/download/${KEYS_VERSION}/prod.keys"
fi
print_info "Downloading prod.keys from: $PROD_KEYS_URL"
if curl -L -o "$KEYS_DIR/prod.keys" "$PROD_KEYS_URL"; then
print_success "prod.keys downloaded successfully"
else
print_warning "Failed to download prod.keys from $PROD_KEYS_URL."
get_firmware_versions || true
exit 1
fi
}
download_firmware() {
if [[ "$SKIP_KEYS" == true ]]; then
print_info "Skipping firmware download"
return
fi
print_info "Preparing to download firmware..."
ensure_keys_version
# Determine firmware directory based on emulator
if [[ "$EMULATOR" == "citron" || "$EMULATOR" == "eden" ]]; then
if [[ "$OS" == "linux" ]]; then
NAND_DIR=$(get_emulator_config "linux_base")"/nand/system/Contents/registered"
else
NAND_DIR="$INSTALL_DIR/user/nand/system/Contents/registered"
fi
elif [[ "$EMULATOR" == "ryujinx" ]]; then
if [[ "$OS" == "linux" ]]; then
NAND_DIR="$HOME/.config/Ryujinx/bis/system/Contents/registered"
else
NAND_DIR="$INSTALL_DIR/bis/system/Contents/registered"
fi
fi
mkdir -p "$NAND_DIR"
if [[ -z "$FIRMWARE_URL" ]]; then
FIRMWARE_URL="https://github.com/THZoria/NX_Firmware/releases/download/${KEYS_VERSION}/Firmware.${KEYS_VERSION}.zip"
fi
if [[ -z "$TEMP_DIR" || ! -d "$TEMP_DIR" ]]; then
TEMP_DIR=$(mktemp -d)
fi
print_info "Downloading firmware from: $FIRMWARE_URL"
if curl -L -o "$TEMP_DIR/firmware.zip" "$FIRMWARE_URL"; then
print_info "Extracting firmware..."
if [[ "$EMULATOR" == "citron" || "$EMULATOR" == "eden" ]]; then
# Citron/Eden: direct extraction
if unzip -o -q "$TEMP_DIR/firmware.zip" -d "$NAND_DIR/"; then
print_success "Firmware downloaded and extracted successfully"
else
print_warning "Downloaded firmware but failed to extract it. File may be different than expected."
get_firmware_versions || true
exit 1
fi
elif [[ "$EMULATOR" == "ryujinx" ]]; then
# Ryujinx: special handling - extract to temp, then process each file
local temp_firmware="$TEMP_DIR/firmware_extract"
mkdir -p "$temp_firmware"
if unzip -o -q "$TEMP_DIR/firmware.zip" -d "$temp_firmware/"; then
print_info "Processing firmware files for Ryujinx..."
# For each file in the extracted firmware
for file in "$temp_firmware"/*; do
if [[ -f "$file" ]]; then
local filename=$(basename "$file")
# Create a folder with the filename (including extension)
local target_dir="$NAND_DIR/$filename"
mkdir -p "$target_dir"
# Move the file into it as '00' (no extension)
mv "$file" "$target_dir/00"
print_info "Processed: $filename"
fi
done
print_success "Firmware downloaded and processed successfully"
else
print_warning "Downloaded firmware but failed to extract it. File may be different than expected."
get_firmware_versions || true
exit 1
fi
fi
else
print_warning "Failed to download firmware from $FIRMWARE_URL."
get_firmware_versions || true
exit 1
fi
}
download_keys_and_firmware() {
download_keys
download_firmware
}
create_desktop_shortcut() {
local desktop_name=$(get_emulator_config "desktop_name")
local desktop_comment=$(get_emulator_config "desktop_comment")
if [[ "$OS" == "linux" ]]; then
print_info "Creating desktop shortcut..."
# Get desktop path from user-dirs.dirs, fallback to $HOME/Desktop
if [[ -f "$HOME/.config/user-dirs.dirs" ]]; then
local desktop_dir=$(grep XDG_DESKTOP_DIR "$HOME/.config/user-dirs.dirs" | cut -d'=' -f2 | tr -d '"')
# Replace $HOME with actual path
desktop_dir="${desktop_dir/#\$HOME/$HOME}"
if [[ -n "$desktop_dir" && -d "$desktop_dir" ]]; then
DESKTOP_FILE="$desktop_dir/${EMULATOR}.desktop"
else
mkdir -p "$HOME/Desktop"
DESKTOP_FILE="$HOME/Desktop/${EMULATOR}.desktop"
fi
else
mkdir -p "$HOME/Desktop"
DESKTOP_FILE="$HOME/Desktop/${EMULATOR}.desktop"
fi
# Determine executable name
local exec_name="$EMULATOR"
if [[ "$EMULATOR" == "ryujinx" ]]; then
exec_name="Ryujinx"
fi
cat > "$DESKTOP_FILE" << EOF
[Desktop Entry]
Name=$desktop_name
Comment=$desktop_comment
Exec=$INSTALL_DIR/$exec_name
Icon=$INSTALL_DIR/$EMULATOR.png
Terminal=false
Type=Application
Categories=$DESKTOP_CATEGORIES
EOF
chmod +x "$DESKTOP_FILE"
print_success "Desktop shortcut created"
elif [[ "$OS" == "windows" ]]; then
print_info "Creating desktop shortcut..."
WIN_DESKTOP="$(powershell.exe -NoProfile -Command "[Environment]::GetFolderPath('Desktop')" | tr -d '\r')"
SHORTCUT_PATH="$WIN_DESKTOP/$desktop_name.lnk"
# Determine executable name
local target_exe="$EMULATOR.exe"
if [[ "$EMULATOR" == "ryujinx" ]]; then
target_exe="Ryujinx.exe"
fi
TARGET_PATH="$INSTALL_DIR/$target_exe"
TARGET_PATH="$(cygpath -w "$TARGET_PATH")"
echo "$TARGET_PATH"
POWERSHELL_CMD="\$s = (New-Object -COM WScript.Shell).CreateShortcut('$SHORTCUT_PATH')
\$s.TargetPath = '$TARGET_PATH'
\$s.IconLocation = '$TARGET_PATH'
\$s.Save()"
powershell.exe -NoProfile -Command "$POWERSHELL_CMD"
print_success "Desktop shortcut created"
fi
}
cleanup() {
if [[ -n "$TEMP_DIR" && -d "$TEMP_DIR" ]]; then
rm -rf "$TEMP_DIR"
print_info "Cleaned up temporary files"
fi
}
main() {
print_info "Starting $EMULATOR installation..."
setup_emulator_vars
detect_os
set_emu_directory
check_existing_installation
get_latest_release_info
download_emu
install_emu
download_keys_and_firmware
create_desktop_shortcut
cleanup
print_success "$EMULATOR v$VERSION installation completed!"
print_info "Installation directory: $INSTALL_DIR"
if [[ "$OS" == "linux" ]]; then
if [[ "$EMULATOR" == "ryujinx" ]]; then
print_info "You can run $EMULATOR with: $INSTALL_DIR/Ryujinx"
else
print_info "You can run $EMULATOR with: $INSTALL_DIR/$EMULATOR"
fi
elif [[ "$OS" == "windows" ]]; then
print_info "You can run $EMULATOR from: $INSTALL_DIR"
fi
if [[ "$SKIP_KEYS" == false ]]; then
print_info "Keys directory: $KEYS_DIR"
print_info "Firmware directory: $NAND_DIR"
fi
}
trap cleanup EXIT
main "$@
# Get all arguments passed to the script
$bashArgs = $args -join ' '
$git = (Get-Command git.exe -ErrorAction SilentlyContinue).Source
if ($git) {
$bash = Join-Path (Split-Path (Split-Path $git -Parent) -Parent) "git-bash.exe"
} else {
$tmp = "$env:TEMP\PortableGit"
Write-Host "Git not found. Downloading Portable Git..." -ForegroundColor Yellow
Invoke-WebRequest "https://github.com/git-for-windows/git/releases/download/v2.50.1.windows.1/PortableGit-2.50.1-64-bit.7z.exe" -OutFile "$env:TEMP\git.exe"
Start-Process "$env:TEMP\git.exe" -ArgumentList "-y", "-o$tmp" -Wait
$bash = "$tmp\bin\bash.exe"
}
# Build the command with arguments if provided
if ($bashArgs) {
& $bash -lc "curl -fsSL https://gist.githubusercontent.com/kipavy/2e71fd3624c76e4a7d4f256977152973/raw/installSwitchEmu.sh | bash -s -- $bashArgs"
} else {
& $bash -lc "curl -fsSL https://gist.githubusercontent.com/kipavy/2e71fd3624c76e4a7d4f256977152973/raw/installSwitchEmu.sh | bash"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment