Files
OpenDeck/install_opendeck.sh

350 lines
9.8 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
GITHUB_REPO="nekename/OpenDeck"
FLATHUB_APP_ID="me.amankhanna.opendeck"
UDEV_RULES_URL="https://raw.githubusercontent.com/nekename/OpenDeck/refs/heads/release/src-tauri/bundle/40-streamdeck.rules"
if [ -t 1 ]; then
RED="\033[0;31m"
GREEN="\033[0;32m"
YELLOW="\033[0;33m"
BLUE="\033[0;34m"
BOLD="\033[1m"
RESET="\033[0m"
else
RED=""
GREEN=""
YELLOW=""
BLUE=""
BOLD=""
RESET=""
fi
trap 'echo -e "${YELLOW}Need help? Join the Discord: ${BLUE}https://discord.gg/26Nf8rHvaj${RESET}"' EXIT
msg_info() { echo -e "${BLUE}[*]${RESET} $*"; }
msg_ok() { echo -e "${GREEN}[✓] $*${RESET}"; }
msg_warn() { echo -e "${YELLOW}[!] $*${RESET}"; }
msg_error() { echo -e "${RED}[✗] $*${RESET}" >&2; }
has_cmd() { command -v "$1" >/dev/null 2>&1; }
confirm() {
printf "%b$1 [y/N]: %b" "$YELLOW$BOLD" "$RESET"
local ans
if [ -r /dev/tty ]; then
read -r ans </dev/tty
else
read -r ans
fi
case "$ans" in
[yY] | [yY][eE][sS]) return 0 ;;
*) return 1 ;;
esac
}
tty_stdin() {
if [ -r /dev/tty ]; then
"$@" </dev/tty
else
"$@"
fi
}
detect_family() {
if has_cmd rpm-ostree || grep -qi "universal blue" /etc/os-release 2>/dev/null; then
echo "ublue"
elif has_cmd pacman; then
echo "arch"
elif has_cmd zypper || has_cmd dnf || has_cmd rpm; then
echo "rpm"
elif has_cmd apt-get || has_cmd dpkg; then
echo "debian"
else
echo "unknown"
fi
}
fetch_latest_asset() {
local ext="$1"
local api_url="https://api.github.com/repos/${GITHUB_REPO}/releases/latest"
local arch arch_deb arch_rpm arch_pattern download_url
arch="$(uname -m)"
case "$arch" in
x86_64)
arch_deb="amd64"
arch_rpm="x86_64"
;;
aarch64)
arch_deb="arm64"
arch_rpm="aarch64"
;;
*)
msg_error "Unsupported architecture $arch"
exit 1
;;
esac
if [ "$ext" = "deb" ]; then
arch_pattern="${arch_deb}"
else
arch_pattern="${arch_rpm}"
fi
if has_cmd curl; then
download_url=$(curl -s --retry 3 --retry-delay 3 "$api_url" |
grep -Eo "https://[^ \"]+${arch_pattern}\.${ext}([^\"]*)" |
head -n1 || true)
elif has_cmd wget; then
download_url=$(wget -qO- --tries=3 "$api_url" |
grep -Eo "https://[^ \"]+${arch_pattern}\.${ext}([^\"]*)" |
head -n1 || true)
fi
if [ -n "$download_url" ]; then
echo "$download_url"
else
msg_error "Failed to find a .${ext} release asset for arch $arch"
return 1
fi
}
download_with_retry() {
local url="$1"
local dest="$2"
if has_cmd curl; then
curl -L --retry 3 --retry-delay 3 -o "$dest" "$url"
else
wget --tries=3 -O "$dest" "$url"
fi
}
reload_udev_rules() {
msg_info "Reloading udev rules"
if ! sudo udevadm control --reload-rules || ! sudo udevadm trigger; then
msg_error "Failed to reload udev rules; you may be able to restart your computer instead"
return 0
fi
msg_ok "Reloaded udev rules"
}
install_flatpak() {
msg_info "Installing ${FLATHUB_APP_ID} from Flathub"
if confirm "Install OpenDeck system-wide? (No = user install)"; then
if ! flatpak remote-list | grep -q flathub; then
msg_error "Flathub remote not found; please add Flathub before running this script"
exit 1
fi
tty_stdin flatpak install flathub "${FLATHUB_APP_ID}"
else
if ! flatpak remote-list --user | grep -q flathub; then
msg_error "Flathub remote not found; please add Flathub before running this script or try installing system-wide"
exit 1
fi
tty_stdin flatpak install --user flathub "${FLATHUB_APP_ID}"
fi
msg_ok "Installed ${FLATHUB_APP_ID} from Flathub"
msg_info "Installing udev rules"
tmp_rules="$(mktemp --suffix=.rules)"
download_with_retry "$UDEV_RULES_URL" "$tmp_rules"
sudo mv "$tmp_rules" /etc/udev/rules.d/40-streamdeck.rules
sudo chmod 644 /etc/udev/rules.d/40-streamdeck.rules
msg_ok "Installed udev rules"
reload_udev_rules
}
install_deb() {
local dl tmpf
dl=$(fetch_latest_asset "deb")
msg_info "Downloading ${dl##*/}"
tmpf="$(mktemp --suffix=.deb)"
download_with_retry "$dl" "$tmpf"
msg_ok "Downloaded ${dl##*/}"
msg_info "Installing .deb package"
tty_stdin sudo apt-get install --fix-broken "$tmpf"
rm -f "$tmpf"
msg_ok "Installed .deb package"
reload_udev_rules
}
install_rpm() {
local dl tmpf
dl=$(fetch_latest_asset "rpm")
msg_info "Downloading ${dl##*/}"
tmpf="$(mktemp --suffix=.rpm)"
download_with_retry "$dl" "$tmpf"
msg_ok "Downloaded ${dl##*/}"
msg_info "Installing .rpm package"
if has_cmd zypper; then
tty_stdin sudo zypper install --allow-unsigned-rpm "$tmpf"
elif has_cmd dnf; then
tty_stdin sudo dnf install --nogpgcheck "$tmpf"
else
tty_stdin sudo rpm -i --nosignature "$tmpf"
fi
rm -f "$tmpf"
msg_ok "Installed .rpm package"
reload_udev_rules
}
install_arch() {
msg_info "Installing from Arch repositories"
tty_stdin sudo pacman -Sy opendeck
msg_ok "Installed from Arch repositories"
reload_udev_rules
}
install_wine_if_needed() {
if has_cmd wine; then
msg_info "Wine already installed"
return
fi
if confirm "Wine is required for some plugins. If you're not sure if you need to install Wine, you can run this script again later. Install Wine now?"; then
msg_info "Installing Wine"
case "$PKG_FAMILY" in
debian)
tty_stdin sudo apt-get update
tty_stdin sudo apt-get install wine
;;
rpm | ublue)
if has_cmd rpm-ostree; then
tty_stdin sudo rpm-ostree install wine wine-mono
elif has_cmd zypper; then
tty_stdin sudo zypper install wine wine-mono
elif has_cmd dnf; then
tty_stdin sudo dnf install wine wine-mono
else
msg_error "No supported package manager found to install Wine; please install it manually"
fi
;;
arch)
tty_stdin sudo pacman -Sy wine wine-mono
;;
*)
msg_error "No supported package manager found to install Wine; please install it manually"
;;
esac
msg_ok "Installed Wine"
else
msg_warn "Not installing Wine"
fi
}
install_node_if_needed() {
if has_cmd node; then
msg_info "Node.js already installed"
return
fi
if confirm "Node.js is required for some plugins. If you're not sure if you need to install Node.js, you can run this script again later. Install Node.js now?"; then
msg_info "Installing Node.js"
case "$PKG_FAMILY" in
debian)
tty_stdin sudo apt-get update
tty_stdin sudo apt-get install nodejs npm
;;
rpm | ublue)
if has_cmd rpm-ostree; then
tty_stdin sudo rpm-ostree install nodejs npm
elif has_cmd zypper; then
tty_stdin sudo zypper install nodejs npm
elif has_cmd dnf; then
tty_stdin sudo dnf install nodejs npm
else
msg_error "No supported package manager found to install Node.js; please install it manually"
fi
;;
arch)
tty_stdin sudo pacman -Sy nodejs npm
;;
*)
msg_error "No supported package manager found to install Node.js; please install it manually"
;;
esac
msg_ok "Installed Node.js"
else
msg_warn "Not installing Node.js"
fi
}
if [ -n "${OPENDECK_PKG_FAMILY:-}" ]; then
PKG_FAMILY="$OPENDECK_PKG_FAMILY"
case "$PKG_FAMILY" in
debian | rpm | arch | ublue)
msg_info "Using package family '${PKG_FAMILY}' from the OPENDECK_PKG_FAMILY environment variable"
;;
*)
msg_error "Invalid OPENDECK_PKG_FAMILY value '${PKG_FAMILY}'"
msg_error "Supported values: debian, rpm, arch, ublue"
exit 1
;;
esac
else
PKG_FAMILY="$(detect_family)"
msg_info "Detected '${PKG_FAMILY}' package family (set the OPENDECK_PKG_FAMILY environment variable to debian, rpm, arch, or ublue to override)"
fi
case "$PKG_FAMILY" in
debian)
install_deb
;;
rpm)
install_rpm
;;
arch)
install_arch
;;
ublue)
install_flatpak
;;
unknown)
if has_cmd flatpak; then
msg_warn "No native package method found"
msg_info "You can continue by installing with Flatpak; if you experience issues, manually install OpenDeck natively"
if confirm "Install with Flatpak?"; then
install_flatpak
else
msg_error "Installation aborted"
exit 1
fi
else
msg_error "No usable installation method found; please install OpenDeck manually"
exit 1
fi
;;
esac
install_wine_if_needed
install_node_if_needed
msg_ok "Installation complete!"
echo -e "${YELLOW}If you enjoy OpenDeck, please consider starring the project on GitHub: ${BLUE}https://github.com/${GITHUB_REPO}${RESET}"
if confirm "Launch OpenDeck now?"; then
if [[ "$PKG_FAMILY" == "ublue" ]] || { [[ "$PKG_FAMILY" == "unknown" ]] && has_cmd flatpak; }; then
flatpak run "${FLATHUB_APP_ID}" &
msg_ok "Launched OpenDeck using Flatpak"
else
if [ -x /bin/opendeck ]; then
/bin/opendeck &
msg_ok "Launched OpenDeck from /bin"
elif has_cmd opendeck; then
opendeck &
msg_ok "Launched OpenDeck from PATH"
else
msg_warn "OpenDeck executable not found"
fi
fi
fi