Name: sl-toolbox Version: 1.1.1 Release: 100.3.4%{?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 %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 / network audio discovery support..." echo "" need_sudo || { echo "Could not get sudo privileges." pause_for_logs return } sudo dnf install -y pipewire-pulseaudio avahi avahi-tools sudo systemctl enable --now avahi-daemon.service systemctl --user restart pipewire pipewire-pulse wireplumber 2>/dev/null || true 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 } 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-git" ;; "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 ---" \ "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" \ "Create SSH Key" \ "Check for Firmware Updates" \ "Back") case "$choice" in "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 ;; "Create SSH Key") create_ssh_key ;; "Check for Firmware Updates") run_firmware_updates ;; "Back"|"") return ;; esac done } ARCH=$(uname -m) while true; do print_banner if [[ "$ARCH" == "x86_64" ]]; then 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 else 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 fi 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.1-10 - 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