Name: sl-toolbox Version: 1.1.2 Release: 100.1.1%{?dist} Summary: Sl's centralized Fedora package toolbox License: Apache-2.0 URL: https://slsrepo.com BuildArch: noarch Requires: bash Requires: dnf Requires: curl Requires: sudo Requires: gum Requires: ncurses %description Sl's centralized Fedora package toolbox for installing and managing Slash packages from the COPR repository. %prep # Nothing to prepare. %build cat > sl-toolbox <<'EOF' #!/usr/bin/env bash set -u # Initialize the alternate screen and catch force-quits. tput smcup 2>/dev/null || true clear trap 'tput rmcup 2>/dev/null || true; exit 0' SIGINT SIGTERM EXIT pause_for_logs() { echo "" read -r -p "➜ Press Enter to return to menu..." echo "" } print_banner() { clear echo -e "\e[38;5;25m" cat << "BANNER" _____ _ _ _____ _ _ / ___|| ( )___ |_ _|__ ___ | | |__ _____ __ \___ \| |// __| | |/ _ \ / _ \| | '_ \ / _ \ \/ / ___) | | \__ \ | | (_) | (_) | | |_) | (_) > < |____/|_| |___/ |_|\___/ \___/|_|_.__/ \___/_/\_\ BANNER echo -e "\e[0m" echo "" } sl_menu() { gum choose \ --cursor="➜ " \ --cursor.foreground="#42a5f5" \ --selected.foreground="#42a5f5" \ --header.foreground="#1b7ece" \ --selected.bold \ "$@" } need_sudo() { if [ "$EUID" -eq 0 ]; then return 0 fi sudo -v } install_pkg() { local pkg="$1" print_banner echo "Installing $pkg..." echo "" need_sudo || { echo "Could not get sudo privileges." pause_for_logs return } sudo dnf install -y "$pkg" pause_for_logs } enable_slash_copr() { print_banner echo "Enabling SLASH COPR repository..." echo "" need_sudo || { echo "Could not get sudo privileges." pause_for_logs return } sudo dnf install -y dnf-plugins-core sudo dnf copr enable -y slsrepo/slash pause_for_logs } optimize_dnf() { print_banner echo "Optimizing DNF..." echo "" need_sudo || { echo "Could not get sudo privileges." pause_for_logs return } sudo mkdir -p /etc/dnf sudo touch /etc/dnf/dnf.conf sudo grep -q '^fastestmirror=' /etc/dnf/dnf.conf \ && sudo sed -i 's/^fastestmirror=.*/fastestmirror=True/' /etc/dnf/dnf.conf \ || echo 'fastestmirror=True' | sudo tee -a /etc/dnf/dnf.conf >/dev/null sudo grep -q '^max_parallel_downloads=' /etc/dnf/dnf.conf \ && sudo sed -i 's/^max_parallel_downloads=.*/max_parallel_downloads=10/' /etc/dnf/dnf.conf \ || echo 'max_parallel_downloads=10' | sudo tee -a /etc/dnf/dnf.conf >/dev/null sudo grep -q '^defaultyes=' /etc/dnf/dnf.conf \ && sudo sed -i 's/^defaultyes=.*/defaultyes=True/' /etc/dnf/dnf.conf \ || echo 'defaultyes=True' | sudo tee -a /etc/dnf/dnf.conf >/dev/null sudo grep -q '^keepcache=' /etc/dnf/dnf.conf \ && sudo sed -i 's/^keepcache=.*/keepcache=True/' /etc/dnf/dnf.conf \ || echo 'keepcache=True' | sudo tee -a /etc/dnf/dnf.conf >/dev/null echo "" echo "DNF config updated:" grep -E '^(fastestmirror|max_parallel_downloads|defaultyes|keepcache)=' /etc/dnf/dnf.conf || true pause_for_logs } clean_dnf_cache() { print_banner echo "Cleaning DNF cache..." echo "" need_sudo || { echo "Could not get sudo privileges." pause_for_logs return } sudo dnf clean all pause_for_logs } install_dnf_automatic() { print_banner echo "Installing and enabling automatic DNF updates..." echo "" need_sudo || { echo "Could not get sudo privileges." pause_for_logs return } if sudo dnf install -y dnf5-plugin-automatic; then if systemctl list-unit-files dnf5-automatic.timer >/dev/null 2>&1; then sudo systemctl enable --now dnf5-automatic.timer systemctl status dnf5-automatic.timer --no-pager || true else echo "dnf5-plugin-automatic installed, but dnf5-automatic.timer was not found." echo "Trying classic dnf-automatic instead..." sudo dnf install -y dnf-automatic sudo systemctl enable --now dnf-automatic.timer systemctl status dnf-automatic.timer --no-pager || true fi else sudo dnf install -y dnf-automatic sudo systemctl enable --now dnf-automatic.timer systemctl status dnf-automatic.timer --no-pager || true fi pause_for_logs } show_enabled_repos() { print_banner echo "Enabled DNF repositories:" echo "" dnf repolist --enabled || true pause_for_logs } upgrade_system() { print_banner echo "Upgrading Fedora packages..." echo "" need_sudo || { echo "Could not get sudo privileges." pause_for_logs return } sudo dnf upgrade -y pause_for_logs } enable_rpmfusion() { print_banner echo "Enabling RPM Fusion free and nonfree repositories..." echo "" need_sudo || { echo "Could not get sudo privileges." pause_for_logs return } sudo dnf install -y \ "https://mirrors.rpmfusion.org/free/fedora/rpmfusion-free-release-$(rpm -E %%fedora).noarch.rpm" \ "https://mirrors.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-$(rpm -E %%fedora).noarch.rpm" pause_for_logs } enable_flathub() { print_banner echo "Enabling Flathub system-wide..." echo "" need_sudo || { echo "Could not get sudo privileges." pause_for_logs return } sudo dnf install -y flatpak sudo flatpak remote-add --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo pause_for_logs } add_terra_repository() { print_banner echo "Adding Terra repository..." echo "" need_sudo || { echo "Could not get sudo privileges." pause_for_logs return } sudo dnf install -y --nogpgcheck --repofrompath 'terra,https://repos.fyralabs.com/terra$releasever' terra-release pause_for_logs } install_appimage_support() { print_banner echo "Installing AppImage support and Gear Lever..." echo "" need_sudo || { echo "Could not get sudo privileges." pause_for_logs return } sudo dnf install -y fuse-libs flatpak sudo flatpak remote-add --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo flatpak install -y flathub it.mijorus.gearlever pause_for_logs } install_gnome_tools() { print_banner echo "Installing GNOME Tweaks and Extension Manager..." echo "" need_sudo || { echo "Could not get sudo privileges." pause_for_logs return } sudo dnf install -y gnome-tweaks flatpak sudo flatpak remote-add --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo flatpak install -y flathub com.mattjakeman.ExtensionManager pause_for_logs } install_multimedia_codecs() { print_banner echo "Installing multimedia codecs from RPM Fusion..." echo "" echo "This may swap ffmpeg-free for full ffmpeg and upgrade multimedia groups." echo "" need_sudo || { echo "Could not get sudo privileges." pause_for_logs return } sudo dnf swap -y ffmpeg-free ffmpeg --allowerasing || true sudo dnf group upgrade -y multimedia --allowerasing || true sudo dnf group upgrade -y core || true pause_for_logs } install_pipewire_zeroconf() { print_banner echo "Installing PipeWire Zeroconf / AirPlay RAOP discovery support..." echo "" need_sudo || { echo "Could not get sudo privileges." pause_for_logs return } sudo dnf install -y \ pipewire-pulseaudio \ pipewire-config-raop \ avahi \ avahi-tools sudo systemctl enable --now avahi-daemon.service systemctl --user daemon-reload 2>/dev/null || true systemctl --user restart pipewire pipewire-pulse wireplumber 2>/dev/null || true echo "" echo "PipeWire RAOP / AirPlay discovery support installed." echo "AirPlay devices should appear as audio outputs when they are visible on the local network." echo "" pause_for_logs } install_tailscale() { print_banner echo "Installing Tailscale..." echo "" need_sudo || { echo "Could not get sudo privileges." pause_for_logs return } sudo dnf install -y dnf-plugins-core if sudo dnf config-manager addrepo --help >/dev/null 2>&1; then sudo dnf config-manager addrepo --from-repofile=https://pkgs.tailscale.com/stable/fedora/tailscale.repo else sudo dnf config-manager --add-repo https://pkgs.tailscale.com/stable/fedora/tailscale.repo fi sudo dnf install -y tailscale sudo systemctl enable --now tailscaled echo "" echo "Starting Tailscale login..." sudo tailscale up pause_for_logs } install_ghostty() { print_banner echo "Installing Ghostty from the scottames/ghostty COPR..." echo "" need_sudo || { echo "Could not get sudo privileges." pause_for_logs return } sudo dnf install -y dnf-plugins-core sudo dnf copr enable -y scottames/ghostty sudo dnf install -y ghostty pause_for_logs } install_fedora_server_environment() { print_banner echo "Installing Fedora Server Packages..." echo "" echo "This installs the Fedora Server package environment on top of the current system." echo "It does not change the existing disk layout, filesystem choices, or desktop environment." echo "" need_sudo || { echo "Could not get sudo privileges." pause_for_logs return } sudo dnf install -y dnf-plugins-core if sudo dnf environment install -y server-product-environment; then true elif sudo dnf group install -y "Fedora Server Edition"; then true else sudo dnf install -y @^server-product-environment fi sudo systemctl enable --now cockpit.socket || true if systemctl is-active --quiet firewalld; then sudo firewall-cmd --add-service=cockpit --permanent || true sudo firewall-cmd --reload || true fi echo "" echo "Fedora Server Packages installed successfully :)" echo "Cockpit socket enabled successfully :)" echo "" pause_for_logs } install_docker() { print_banner echo "Installing Docker Engine from the official Docker repository..." echo "" need_sudo || { echo "Could not get sudo privileges." pause_for_logs return } sudo dnf install -y dnf-plugins-core if sudo dnf config-manager addrepo --help >/dev/null 2>&1; then sudo dnf config-manager addrepo --from-repofile=https://download.docker.com/linux/fedora/docker-ce.repo else sudo dnf config-manager --add-repo https://download.docker.com/linux/fedora/docker-ce.repo fi sudo dnf install -y \ docker-ce \ docker-ce-cli \ containerd.io \ docker-buildx-plugin \ docker-compose-plugin sudo systemctl enable --now docker.service if getent group docker >/dev/null 2>&1; then sudo usermod -aG docker "$USER" || true echo "" echo "Added $USER to the docker group." echo "Log out and back in before running docker without sudo." fi pause_for_logs } install_virtualization() { print_banner echo "Installing KVM/QEMU/libvirt virtualization tools..." echo "" need_sudo || { echo "Could not get sudo privileges." pause_for_logs return } sudo dnf group install -y --with-optional virtualization || \ sudo dnf install -y \ qemu-kvm \ libvirt \ virt-install \ virt-manager \ virt-viewer \ libguestfs-tools \ edk2-ovmf \ bridge-utils sudo systemctl enable --now libvirtd.service if getent group libvirt >/dev/null 2>&1; then sudo usermod -aG libvirt "$USER" || true echo "" echo "Added $USER to the libvirt group." echo "Log out and back in before managing VMs without extra auth." fi pause_for_logs } create_ssh_key() { print_banner echo "Creating an SSH key if one does not already exist..." echo "" mkdir -p "$HOME/.ssh" chmod 700 "$HOME/.ssh" if [ -f "$HOME/.ssh/id_ed25519" ]; then echo "SSH key already exists:" echo " $HOME/.ssh/id_ed25519" echo "" echo "Public key:" cat "$HOME/.ssh/id_ed25519.pub" 2>/dev/null || true pause_for_logs return fi read -r -p "Email/comment for SSH key: " ssh_comment if [ -z "$ssh_comment" ]; then ssh_comment="$USER@$(hostname)" fi ssh-keygen -t ed25519 -C "$ssh_comment" -f "$HOME/.ssh/id_ed25519" echo "" echo "Public key:" cat "$HOME/.ssh/id_ed25519.pub" pause_for_logs } run_firmware_updates() { print_banner echo "Checking for firmware updates..." echo "" need_sudo || { echo "Could not get sudo privileges." pause_for_logs return } sudo dnf install -y fwupd sudo fwupdmgr refresh --force || true sudo fwupdmgr get-devices || true sudo fwupdmgr get-updates || true sudo fwupdmgr update || true pause_for_logs } install_zen_flatpak() { print_banner echo "Installing Zen Browser from Flathub..." echo "" echo "This is the easiest Zen install path, but KeePassXC browser integration can be problematic with Flatpak browsers." echo "" need_sudo || { echo "Could not get sudo privileges." pause_for_logs return } sudo dnf install -y flatpak sudo flatpak remote-add --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo flatpak install -y flathub app.zen_browser.zen pause_for_logs } install_zen_stable_tarball() { print_banner echo "Installing Zen Browser stable tarball using the official install script..." echo "" curl -fsSL https://github.com/zen-browser/updates-server/raw/refs/heads/main/install.sh | bash pause_for_logs } install_zen_twilight_tarball() { print_banner echo "Installing Zen Browser Twilight tarball using the official install script..." echo "" curl -fsSL https://github.com/zen-browser/updates-server/raw/refs/heads/main/install-twilight.sh | bash pause_for_logs } github_latest_asset() { local pattern="$1" curl -fsSL https://api.github.com/repos/zen-browser/desktop/releases/latest \ | grep -oE '"browser_download_url": "[^"]+"' \ | cut -d '"' -f 4 \ | grep -Ei "$pattern" \ | head -n 1 } install_zen_stable_appimage() { print_banner echo "Installing Zen Browser stable AppImage..." echo "" local arch local arch_pattern local url local appdir local appimage arch="$(uname -m)" case "$arch" in x86_64) arch_pattern='(x86_64|amd64)' ;; aarch64) arch_pattern='(aarch64|arm64)' ;; *) echo "Unsupported architecture for Zen AppImage auto-download: $arch" pause_for_logs return ;; esac url="$(github_latest_asset 'AppImage$' | grep -Ei "$arch_pattern" | head -n 1 || true)" if [ -z "$url" ]; then url="$(github_latest_asset 'AppImage$' | head -n 1 || true)" fi if [ -z "$url" ]; then echo "Could not find a Zen AppImage asset in the latest GitHub release." echo "Use the tarball script option instead." pause_for_logs return fi appdir="$HOME/Applications" appimage="$appdir/Zen-Browser.AppImage" mkdir -p "$appdir" curl -fL "$url" -o "$appimage" chmod +x "$appimage" mkdir -p "$HOME/.local/share/applications" cat > "$HOME/.local/share/applications/zen-browser-appimage.desktop" </dev/null 2>&1 || true echo "" echo "Zen AppImage installed at:" echo " $appimage" pause_for_logs } install_keepassxc() { print_banner echo "Installing KeePassXC..." echo "" need_sudo || { echo "Could not get sudo privileges." pause_for_logs return } sudo dnf install -y keepassxc pause_for_logs } configure_keepassxc_browser_helper() { print_banner echo "Configuring KeePassXC browser native messaging helper..." echo "" echo "This is mainly useful for non-Flatpak Zen installs." echo "For Flatpak Zen, this is best-effort only because Flatpak browser native messaging is limited." echo "" need_sudo || { echo "Could not get sudo privileges." pause_for_logs return } sudo dnf install -y keepassxc local proxy local manifest_name local manifest_json proxy="$(command -v keepassxc-proxy || true)" manifest_name="org.keepassxc.keepassxc_browser.json" if [ -z "$proxy" ]; then echo "Could not find keepassxc-proxy." echo "Make sure the Fedora keepassxc package installed it." pause_for_logs return fi manifest_json="$(mktemp)" cat > "$manifest_json" < "$flatpak_helper" < "$flatpak_manifest" </dev/null 2>&1 || true rm -f "$flatpak_manifest" fi rm -f "$manifest_json" echo "" echo "KeePassXC native messaging manifests were created." echo "" echo "Next steps:" echo " 1. Open KeePassXC." echo " 2. Enable Browser Integration in KeePassXC settings." echo " 3. Install the KeePassXC-Browser extension in Zen." echo " 4. Restart Zen." echo "" pause_for_logs } zen_browser_menu() { while true; do print_banner choice=$(sl_menu --header="--- Zen Browser ---" \ "Install Zen from Flathub" \ "Install Zen Stable Tarball" \ "Install Zen Twilight Tarball" \ "Install Zen Stable AppImage" \ "Install KeePassXC" \ "Configure KeePassXC Browser Helper" \ "Back") case "$choice" in "Install Zen from Flathub") install_zen_flatpak ;; "Install Zen Stable Tarball") install_zen_stable_tarball ;; "Install Zen Twilight Tarball") install_zen_twilight_tarball ;; "Install Zen Stable AppImage") install_zen_stable_appimage ;; "Install KeePassXC") install_keepassxc ;; "Configure KeePassXC Browser Helper") configure_keepassxc_browser_helper ;; "Back"|"") return ;; esac done } desktop_pkgs_menu() { while true; do print_banner choice=$(sl_menu --header="--- Sl's Desktop ---" \ "Full Desktop (sl-desktop-full)" \ "sl-greeter & sl-lock (sl-desktop-utils)" \ "Desktop Assets (sl-desktop-assets)" \ "Blue DMS Theme (sl-blue-dms-theme)" \ "Back") case "$choice" in "Full Desktop (sl-desktop-full)") install_pkg "sl-desktop-full" ;; "sl-greeter & sl-lock (sl-desktop-utils)") install_pkg "sl-desktop-utils" ;; "Desktop Assets (sl-desktop-assets)") install_pkg "sl-desktop-assets" ;; "Blue DMS Theme (sl-blue-dms-theme)") install_pkg "sl-blue-dms-theme" ;; "Back"|"") return ;; esac done } bg_pkgs_menu() { while true; do print_banner choice=$(sl_menu --header="--- Sl's Daily Background ---" \ "From Bing (sl-daily-background-bing)" \ "From NASA (sl-daily-background-nasa)" \ "From Unsplash (sl-daily-background-unsplash)" \ "Back") case "$choice" in "From Bing (sl-daily-background-bing)") install_pkg "sl-daily-background-bing" ;; "From NASA (sl-daily-background-nasa)") install_pkg "sl-daily-background-nasa" ;; "From Unsplash (sl-daily-background-unsplash)") install_pkg "sl-daily-background-unsplash" ;; "Back"|"") return ;; esac done } packages_menu() { while true; do print_banner choice=$(sl_menu --header="--- Install Sl’s Packages ---" \ "Sl’s Desktop" \ "Sl’s Daily Background" \ "Sl’s Display Mirror" \ "Sl’s Disklabel Utils" \ "Sl’s XKB Mac Layouts" \ "Meerkrite TUI Editor" \ "Back") case "$choice" in "Sl’s Desktop") desktop_pkgs_menu ;; "Sl’s Daily Background") bg_pkgs_menu ;; "Sl’s Display Mirror") install_pkg "sl-display-mirror" ;; "Sl’s Disklabel Utils") install_pkg "sl-disklabel-utils" ;; "Sl’s XKB Mac Layouts") install_pkg "sl-xkb-mac-layouts" ;; "Meerkrite TUI Editor") install_pkg "meerkrite-tui" ;; "Back"|"") return ;; esac done } useful_fedora_commands_menu() { while true; do print_banner choice=$(sl_menu --header="--- Useful Fedora Commands ---" \ "Check for Firmware Updates" \ "Optimize DNF" \ "Clean DNF Cache" \ "Enable DNF Automatic Updates" \ "Show Enabled Repositories" \ "Enable RPM Fusion" \ "Enable Flathub" \ "Add Terra Repository" \ "Install AppImage Support & Gear Lever" \ "Install GNOME Tweaks & Extension Manager" \ "Install Multimedia Codecs" \ "Install PipeWire Zeroconf Support" \ "Install Tailscale" \ "Install Zen Browser" \ "Install Ghostty (from COPR)" \ "Install Fedora Server Packages" \ "Install Docker Engine" \ "Install Virtualization Tools" \ "Create SSH Key" \ "Back") case "$choice" in "Check for Firmware Updates") run_firmware_updates ;; "Optimize DNF") optimize_dnf ;; "Clean DNF Cache") clean_dnf_cache ;; "Enable DNF Automatic Updates") install_dnf_automatic ;; "Show Enabled Repositories") show_enabled_repos ;; "Enable RPM Fusion") enable_rpmfusion ;; "Enable Flathub") enable_flathub ;; "Add Terra Repository") add_terra_repository ;; "Install AppImage Support & Gear Lever") install_appimage_support ;; "Install GNOME Tweaks & Extension Manager") install_gnome_tools ;; "Install Multimedia Codecs") install_multimedia_codecs ;; "Install PipeWire Zeroconf Support") install_pipewire_zeroconf ;; "Install Tailscale") install_tailscale ;; "Install Zen Browser") zen_browser_menu ;; "Install Ghostty (from COPR)") install_ghostty ;; "Install Fedora Server Packages") install_fedora_server_environment ;; "Install Docker Engine") install_docker ;; "Install Virtualization Tools") install_virtualization ;; "Create SSH Key") create_ssh_key ;; "Back"|"") return ;; esac done } ARCH=$(uname -m) while true; do print_banner choice=$(sl_menu --header="--- Welcome to Sl's Fedora Toolbox ($ARCH) ---" \ "Enable the SLASH COPR Repository" \ "Install Sl’s Packages" \ "Upgrade Fedora Packages" \ "Useful Fedora Commands" \ "Quit") case "$choice" in "Enable the SLASH COPR Repository") enable_slash_copr ;; "Install Sl’s Packages") packages_menu ;; "Upgrade Fedora Packages") upgrade_system ;; "Useful Fedora Commands") useful_fedora_commands_menu ;; "Quit"|"") tput rmcup 2>/dev/null || true exit 0 ;; esac done EOF %install install -Dm755 sl-toolbox %{buildroot}%{_bindir}/sl-toolbox %files %{_bindir}/sl-toolbox %changelog * Sat Jun 20 2026 Sl (Shahaf Levi) - 1.1.2-1 - Reorder Useful Fedora Commands menu - Add DNF automatic updates action - Add PipeWire Zeroconf support action - Add Zen Browser submenu with Flathub, tarball, AppImage, and KeePassXC helper options - Add Gear Lever to AppImage support action - Keep Fedora build filtered to Fedora-safe package management actions only