bitzdots
gitlabLean Hyprland dotfiles with automatic matugen theming. Low-end optimized, full-stack auto-coloring, 26 Jinja2 templates. Rofi-powered menus, waybar modules, screenshot/recording, event-driven cache daemon.
clone
https://gitlab.com/bitzzdev/bitzdots.gitarchlinuxdotfileshyprlandhyprland-dotfileslow-endminimalricingwallustwaybarwayland
#!/bin/bash# ============================================================# bitzdots — Automated Installer with matugen theming# ============================================================set -euo pipefailDOTFILES_DIR="$(cd "$(dirname "$0")" && pwd)"CONFIG_DIR="${XDG_CONFIG_HOME:-$HOME/.config}"CACHE_DIR="${XDG_CACHE_HOME:-$HOME/.cache}"WALL_DIR="${WALLPAPER_DIR:-$HOME/Pictures/Wallpapers}"RED='\033[0;31m'GREEN='\033[0;32m'YELLOW='\033[1;33m'CYAN='\033[0;36m'NC='\033[0m'log() { echo -e "${CYAN}[bitzdots]${NC} $1"; }ok() { echo -e "${GREEN}[ ok ]${NC} $1"; }warn() { echo -e "${YELLOW}[ warn ]${NC} $1"; }fail() { echo -e "${RED}[ fail ]${NC} $1"; exit 1; }detect_distro() {if [ -f /etc/arch-release ]; thenecho "arch"elif [ -f /etc/debian_version ]; thenecho "debian"elif [ -f /etc/fedora-release ]; thenecho "fedora"elif command -v nix-env &>/dev/null; thenecho "nixos"elseecho "unknown"fi}install_deps() {local distrodistro=$(detect_distro)log "Detected distro: $distro"case "$distro" inarch)log "Installing packages (Arch)..."# Stage 1: guaranteed repo packages (core + extra) via pacmanlocal repo_pkgs=(hyprland waybar swaync rofi kitty cavahyprpicker wl-clipboard playerctl pavucontrolpolkit-kde-agent grim slurp cliphist hyprlock ffmpegbtop pulsemixer wf-recorder pythonpower-profiles-daemon breeze inotify-tools fish fastfetchbrightnessctl bluez bluez-utils libnotify networkmanagerwireplumber pipewire-pulse curl jq imagemagicknautilus wofi papirus-icon-theme rustqt5ct qt6ct matugen)sudo pacman -S --needed --noconfirm "${repo_pkgs[@]}" || \warn "Some repo packages failed — the rest were likely installed"ok "Repo packages installed"# Stage 2: packages that may be in community or AUR# Install individually so a single failure doesn't block the restinstall_aur_pkg() {local pkg=$1if command -v paru &>/dev/null; thenparu -S --needed --noconfirm "$pkg" 2>&1 || return 1elif command -v yay &>/dev/null; thenyay -S --needed --noconfirm "$pkg" 2>&1 || return 1elsereturn 1fi}for pkg in wlogout bluetui awww impala matugen; doif command -v "$pkg" &>/dev/null; thencontinuefilog "Installing $pkg..."if install_aur_pkg "$pkg"; thenok " $pkg installed"elif [ "$pkg" = matugen ] && command -v cargo &>/dev/null; thenwarn " $pkg AUR build failed — trying cargo..."cargo install matugen && ok " matugen installed via cargo" || warn " matugen install failed"elif [ "$pkg" = bluetui ] && command -v cargo &>/dev/null; thenwarn " $pkg AUR build failed — trying cargo..."cargo install bluetui && ok " bluetui installed via cargo" || warn " bluetui install failed"elif [ "$pkg" = impala ] && command -v cargo &>/dev/null; thenwarn " $pkg AUR build failed — trying cargo..."cargo install impala && ok " impala installed via cargo" || warn " impala install failed"elsewarn " $pkg not installed — install manually if needed"fidone# Try to replace xdg-desktop-portal-hyprland with git version (fixes CPU loop)if pacman -Q xdg-desktop-portal-hyprland 2>/dev/null | grep -q "1.4" && \! pacman -Q xdg-desktop-portal-hyprland-git 2>/dev/null; thenlog "Installing xdg-desktop-portal-hyprland-git (fixes CPU loop)..."install_aur_pkg xdg-desktop-portal-hyprland-git || \warn " Could not replace portal — will use autostart workaround instead"fi;;fedora)log "Installing packages (Fedora)..."sudo dnf install -y \hyprland waybar swaync wlogout rofi kitty cava \awww hyprpicker wl-clipboard playerctl pavucontrol \polkit-kde-agent grim slurp cliphist hyprlock ffmpeg \inotify-tools fish fastfetch btop pulsemixer \wf-recorder python3 impala \brightnessctl bluez libnotify \NetworkManager wireplumber pipewire-pulseaudio \curl jq ImageMagick nautilus wofi papirus-icon-theme \qt5ct qt6ctif ! command -v matugen &>/dev/null && command -v cargo &>/dev/null; thenlog "Installing matugen via cargo..."cargo install matugen 2>/dev/null || warn "Could not install matugen via cargo"fi;;debian)log "Installing packages (Debian/Ubuntu)..."sudo apt install -y \hyprland waybar swaync wlogout rofi kitty cava \awww hyprpicker wl-clipboard playerctl pavucontrol \polkit-kde-agent grim slurp cliphist hyprlock ffmpeg \inotify-tools fish fastfetch btop pulsemixer \wf-recorder python3 \brightnessctl bluez bluez-utils libnotify-bin \network-manager wireplumber pipewire-pulse \curl jq imagemagick nautilus wofi papirus-icon-theme \qt5ct qt6ctif ! command -v matugen &>/dev/null && command -v cargo &>/dev/null; thenlog "Installing matugen via cargo..."cargo install matugen 2>/dev/null || warn "Could not install matugen via cargo"fi;;nixos)log "NixOS detected — add these to your configuration.nix:"echo " services.awww.enable = true;"echo " programs.waybar.enable = true;"echo " programs.rofi.enable = true;"echo " programs.hyprland.enable = true;"echo " environment.systemPackages = with pkgs; ["echo " hyprland matugen swaync wlogout kitty cava inotify-tools"echo " hyprpicker wl-clipboard playerctl pavucontrol"echo " polkit-kde-agent grim slurp cliphist hyprlock ffmpeg"echo " fish fastfetch btop pulsemixer wf-recorder python3"echo " brightnessctl bluez bluez-utils libnotify"echo " networkmanager wireplumber pipewire-pulse"echo " curl jq imagemagick nautilus wofi papirus-icon-theme"echo " qt5ct qt6ct"echo " ];"echo " services.bluetooth.enable = true;";;*)warn "Unknown distro. Please install manually:"echo " - hyprland (window manager)"echo " - matugen (https://github.com/InioX/matugen)"echo " - waybar, swaync, wlogout, rofi, kitty, cava"echo " - awww, hyprpicker, wl-clipboard, playerctl"echo " - pavucontrol, polkit-kde-agent, grim, slurp, cliphist"echo " - hyprlock, ffmpeg, inotify-tools"echo " - fish, fastfetch, btop, pulsemixer, wf-recorder, python3"echo " - brightnessctl, bluez, bluez-utils, libnotify"echo " - networkmanager, wireplumber, pipewire-pulse, curl, jq"echo " - imagemagick, nautilus, wofi, papirus-icon-theme"echo " - chromium (dark mode policy will be created)"echo " - qt5ct, qt6ct, kvantum (for Qt dark theme)";;esac}install_nerd_font() {if fc-list :family 2>/dev/null | grep -qi "JetBrainsMono Nerd Font"; thenok "JetBrainsMono Nerd Font already installed"returnfilog "Installing JetBrainsMono Nerd Font..."if command -v paru &>/dev/null; thenparu -S --needed --noconfirm ttf-jetbrains-mono-nerd && returnfiif command -v yay &>/dev/null; thenyay -S --needed --noconfirm ttf-jetbrains-mono-nerd && returnfiwarn "No AUR helper found. Install manually: paru -S ttf-jetbrains-mono-nerd"}link_config() {local src="$1"local dest="$2"local name="$3"[ -e "$src" ] || returnif [ -e "$dest" ] && [ ! -L "$dest" ]; thenwarn "$name config exists at $dest — backing up to ${dest}.bak"mv "$dest" "${dest}.bak"fiif [ -L "$dest" ]; thenreturnfiln -sf "$src" "$dest"}setup_wallpapers() {mkdir -p "$WALL_DIR" "$WALL_DIR/live"for f in "$DOTFILES_DIR/hypr/wallpapers"/* "$DOTFILES_DIR/Wallpapers"/*; do[ -f "$f" ] || continuecp -n "$f" "$WALL_DIR/" 2>/dev/null || truedoneok "Wallpapers ready: $WALL_DIR/"}setup_cache() {mkdir -p "$CACHE_DIR"}setup_runcat() {local module_dir="$CONFIG_DIR/waybar/modules/runcat-text"[ -d "$DOTFILES_DIR/waybar/modules/runcat-text" ] || returnmkdir -p "$module_dir"cp "$DOTFILES_DIR/waybar/modules/runcat-text"/* "$module_dir/"local font_dir="${XDG_DATA_HOME:-$HOME/.local/share}/fonts"mkdir -p "$font_dir"if [ -f "$module_dir/runcat.ttf" ] && ! fc-list :family 2>/dev/null | grep -qi "runcat"; thencp "$module_dir/runcat.ttf" "$font_dir/"fc-cache -f 2>/dev/null || truefiif [ ! -f "$module_dir/.venv/bin/python" ] && command -v python &>/dev/null; thenpython -m venv "$module_dir/.venv""$module_dir/.venv/bin/pip" install -q "$module_dir/requirements.txt" 2>/dev/null || \"$module_dir/.venv/bin/pip" install -q pyjson5 2>/dev/null || truefiok "runcat-text setup complete"}cleanup_wallust() {log "Cleaning up legacy wallust files and services..."systemctl --user stop wallust-cache-daemon.service 2>/dev/null || truesystemctl --user disable wallust-cache-daemon.service 2>/dev/null || truerm -f "${XDG_CONFIG_HOME:-$HOME/.config}/systemd/user/wallust-cache-daemon.service"rm -rf "$CONFIG_DIR/wallust"rm -rf "$CACHE_DIR/wallust"rm -rf "$CACHE_DIR/wallust-thumbs"rm -rf "$CACHE_DIR/wallust-backup"ok "Legacy wallust cleanup complete"}install_scripts() {local scripts_dir="$CONFIG_DIR/matugen"mkdir -p "$scripts_dir/templates"for s in reload-theme.sh wallpaper-select.sh cache-wallpapers.sh matugen-cache-daemon.sh record-fullscreen.sh record-region.sh recording-indicator.sh wifi-fix.sh font-switch.sh; doln -sf "$DOTFILES_DIR/scripts/$s" "$scripts_dir/$s"doneln -sf "$DOTFILES_DIR/matugen/config.toml" "$scripts_dir/config.toml"for t in "$DOTFILES_DIR/matugen/templates"/*; do[ -e "$t" ] && ln -sf "$t" "$scripts_dir/templates/"donemkdir -p "$HOME/.local/bin"ln -sf "$DOTFILES_DIR/scripts/hyprlogout" "$HOME/.local/bin/hyprlogout"ln -sf "$DOTFILES_DIR/scripts/font-switch.sh" "$HOME/.local/bin/font-switch.sh"ln -sf "$DOTFILES_DIR/scripts/fetch-quick-shelf.sh" "$HOME/.local/bin/fetch-quick-shelf"mkdir -p "$CONFIG_DIR/quick/shelf"ln -sf "$DOTFILES_DIR/scripts/fetch-quick-shelf.sh" "$CONFIG_DIR/quick/shelf/fetch-binary.sh"ok "Matugen scripts and templates linked"}make_executable() {for d in "$CONFIG_DIR/waybar/scripts" "$CONFIG_DIR/rofi/scripts" "$CONFIG_DIR/matugen"; dofor s in "$d"/*.sh; dochmod +x "$s" 2>/dev/null || truedonedonechmod +x "$HOME/.local/bin/hyprlogout" "$HOME/.local/bin/font-switch.sh" "$HOME/.local/bin/fetch-quick-shelf" 2>/dev/null || truechmod +x "$DOTFILES_DIR/scripts/fetch-quick-shelf.sh" 2>/dev/null || trueok "Scripts made executable"}install_waybar_config() {mkdir -p "$CONFIG_DIR/waybar/scripts" "$CONFIG_DIR/waybar/colors"link_config "$DOTFILES_DIR/waybar/config.jsonc" "$CONFIG_DIR/waybar/config.jsonc" "waybar"link_config "$DOTFILES_DIR/waybar/style.css" "$CONFIG_DIR/waybar/style.css" "waybar"link_config "$DOTFILES_DIR/waybar/colors/teto.css" "$CONFIG_DIR/waybar/colors/teto.css" "waybar"link_config "$DOTFILES_DIR/waybar/scripts/launch.sh" "$CONFIG_DIR/waybar/scripts/launch.sh" "waybar"link_config "$DOTFILES_DIR/waybar/scripts/media.sh" "$CONFIG_DIR/waybar/scripts/media.sh" "waybar"link_config "$DOTFILES_DIR/waybar/scripts/weather.sh" "$CONFIG_DIR/waybar/scripts/weather.sh" "waybar"for s in brightness.sh brightness-adjust.sh notification.sh power-profile.sh power-profile-switch.sh system-power.sh workspaces.sh workspace-click.sh workspace-next.sh workspace-prev.sh tui-wifi.sh tui-bluetooth.sh tui-audio.sh tui-cpu.sh shelf-status.sh; dolink_config "$DOTFILES_DIR/waybar/scripts/$s" "$CONFIG_DIR/waybar/scripts/$s" "waybar"donefor s in "$DOTFILES_DIR/scripts"/record*.sh; dolink_config "$s" "$CONFIG_DIR/waybar/scripts/$(basename "$s")" "waybar"donelink_config "$DOTFILES_DIR/scripts/workspace-monitor.sh" "$CONFIG_DIR/waybar/scripts/workspace-monitor.sh" "waybar"}install_hypr_config() {mkdir -p "$CONFIG_DIR/hypr"for f in "$DOTFILES_DIR/hypr"/*.lua; dolink_config "$f" "$CONFIG_DIR/hypr/$(basename "$f")" "hyprland"done}install_swaync_config() {mkdir -p "$CONFIG_DIR/swaync"link_config "$DOTFILES_DIR/swaync/config.json" "$CONFIG_DIR/swaync/config.json" "swaync"link_config "$DOTFILES_DIR/swaync/style.css" "$CONFIG_DIR/swaync/style.css" "swaync"link_config "$DOTFILES_DIR/swaync/media-swaync.sh" "$CONFIG_DIR/swaync/media-swaync.sh" "swaync"link_config "$DOTFILES_DIR/swaync/bt-status.sh" "$CONFIG_DIR/swaync/bt-status.sh" "swaync"}install_gtk_config() {mkdir -p "$CONFIG_DIR/gtk-3.0" "$CONFIG_DIR/gtk-4.0"link_config "$DOTFILES_DIR/gtk/gtk-3.0/settings.ini" "$CONFIG_DIR/gtk-3.0/settings.ini" "gtk3"link_config "$DOTFILES_DIR/gtk/gtk-4.0/settings.ini" "$CONFIG_DIR/gtk-4.0/settings.ini" "gtk4"}install_qt_config() {mkdir -p "$CONFIG_DIR/qt5ct"link_config "$DOTFILES_DIR/qt5ct/qt5ct.conf" "$CONFIG_DIR/qt5ct/qt5ct.conf" "qt5ct"# qt6ct config is auto-generated by matugen from templateok "Dark theme enabled for GTK + Qt apps"}install_wlogout_config() {mkdir -p "$CONFIG_DIR/wlogout/assets" "$CONFIG_DIR/wlogout/icons" "$CONFIG_DIR/wlogout/actions"link_config "$DOTFILES_DIR/wlogout/style.css" "$CONFIG_DIR/wlogout/style.css" "wlogout"link_config "$DOTFILES_DIR/wlogout/layout" "$CONFIG_DIR/wlogout/layout" "wlogout"for d in assets icons actions; dofor f in "$DOTFILES_DIR/wlogout/$d"/*; dolink_config "$f" "$CONFIG_DIR/wlogout/$d/$(basename "$f")" "wlogout"donedone}install_rofi_config() {mkdir -p "$CONFIG_DIR/rofi/themes" "$CONFIG_DIR/rofi/colors" "$CONFIG_DIR/rofi/launchers" "$CONFIG_DIR/rofi/scripts" "$CONFIG_DIR/rofi/icons"link_config "$DOTFILES_DIR/rofi/config.rasi" "$CONFIG_DIR/rofi/config.rasi" "rofi"for d in colors themes; dofor f in "$DOTFILES_DIR/rofi/$d"/*.rasi; dolink_config "$f" "$CONFIG_DIR/rofi/$d/$(basename "$f")" "rofi"donedonefor f in "$DOTFILES_DIR/rofi/launchers"/*; do[ -f "$f" ] && link_config "$f" "$CONFIG_DIR/rofi/launchers/$(basename "$f")" "rofi"donelink_config "$DOTFILES_DIR/rofi/scripts/script_wallpaper.sh" "$CONFIG_DIR/rofi/scripts/script_wallpaper.sh" "rofi"link_config "$DOTFILES_DIR/rofi/scripts/system-power.sh" "$CONFIG_DIR/rofi/scripts/system-power.sh" "rofi"link_config "$DOTFILES_DIR/rofi/scripts/clipboard.sh" "$CONFIG_DIR/rofi/scripts/clipboard.sh" "rofi"link_config "$DOTFILES_DIR/rofi/scripts/spotlight.sh" "$CONFIG_DIR/rofi/scripts/spotlight.sh" "rofi"# Iconslink_config "$DOTFILES_DIR/icons/lock-outline-sharp.svg" "$CONFIG_DIR/rofi/icons/lock.svg" "rofi"link_config "$DOTFILES_DIR/icons/logout-sharp.svg" "$CONFIG_DIR/rofi/icons/logout.svg" "rofi"link_config "$DOTFILES_DIR/icons/sleep.svg" "$CONFIG_DIR/rofi/icons/sleep.svg" "rofi"link_config "$DOTFILES_DIR/icons/reboot.svg" "$CONFIG_DIR/rofi/icons/reboot.svg" "rofi"link_config "$DOTFILES_DIR/icons/shutdown.svg" "$CONFIG_DIR/rofi/icons/shutdown.svg" "rofi"link_config "$DOTFILES_DIR/icons/cancel-outline.svg" "$CONFIG_DIR/rofi/icons/cancel.svg" "rofi"link_config "$DOTFILES_DIR/icons/static.svg" "$CONFIG_DIR/rofi/icons/static.svg" "rofi"link_config "$DOTFILES_DIR/icons/live.svg" "$CONFIG_DIR/rofi/icons/live.svg" "rofi"}install_cava_config() {mkdir -p "$CONFIG_DIR/cava/themes" "$CONFIG_DIR/cava/shaders"link_config "$DOTFILES_DIR/cava/config" "$CONFIG_DIR/cava/config" "cava"for f in "$DOTFILES_DIR/cava/shaders"/*; dolink_config "$f" "$CONFIG_DIR/cava/shaders/$(basename "$f")" "cava"done}link_dotfiles() {log "Linking dotfiles..."install_waybar_configinstall_hypr_configinstall_swaync_configinstall_gtk_configinstall_qt_configinstall_wlogout_configinstall_rofi_configinstall_cava_configmkdir -p "$CONFIG_DIR/kitty"link_config "$DOTFILES_DIR/kitty/kitty.conf" "$CONFIG_DIR/kitty/kitty.conf" "kitty"mkdir -p "$CONFIG_DIR/environment.d"link_config "$DOTFILES_DIR/environment.d/qt.conf" "$CONFIG_DIR/environment.d/qt.conf" "qt"mkdir -p "$CONFIG_DIR/fish"link_config "$DOTFILES_DIR/fish/config.fish" "$CONFIG_DIR/fish/config.fish" "fish"mkdir -p "$CONFIG_DIR/fastfetch"link_config "$DOTFILES_DIR/fastfetch/config.jsonc" "$CONFIG_DIR/fastfetch/config.jsonc" "fastfetch"link_config "$DOTFILES_DIR/fastfetch/bitz.txt" "$CONFIG_DIR/fastfetch/bitz.txt" "fastfetch"}fix_paths() {log "Fixing hardcoded paths..."local files=("$DOTFILES_DIR/rofi/config.rasi""$DOTFILES_DIR/rofi/scripts/script_wallpaper.sh""$DOTFILES_DIR/rofi/launchers/type-6/style-4.rasi""$DOTFILES_DIR/rofi/themes/wallpaper-grid.rasi")for file in "${files[@]}"; do[ -f "$file" ] && sed -i "s|/home/lucario|$HOME|g; s|/home/bitz|$HOME|g" "$file" 2>/dev/null || truedoneok "Paths fixed"}add_keybind() {local keybind_file="$CONFIG_DIR/hypr/keybinds.lua"[ -f "$keybind_file" ] || returngrep -q "wallpaper-select" "$keybind_file" 2>/dev/null && returnecho "" >> "$keybind_file"echo "-- Wallpaper selector" >> "$keybind_file"echo 'hl.bind("SUPER + SHIFT + W", hl.dsp.exec_cmd("~/.config/matugen/wallpaper-select.sh"))' >> "$keybind_file"ok "Keybind added: SUPER+SHIFT+W = wallpaper picker"}generate_initial_theme() {command -v matugen &>/dev/null || { warn "matugen not installed — skipping theme generation"; return; }local initial_wall=""local imgfor img in $(find "$WALL_DIR" -maxdepth 1 -type f \( -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.png" -o -iname "*.webp" \) | sort); doif timeout 20 matugen image "$img" --config "$CONFIG_DIR/matugen/config.toml" -q 2>/dev/null; theninitial_wall="$img"breakfidone[ -n "$initial_wall" ] || { warn "No suitable wallpaper found — skipping theme generation"; return; }log "Generating theme from: $(basename "$initial_wall")"echo "$initial_wall" > "$CACHE_DIR/current_wallpaper.txt" 2>/dev/null || trueln -sf "$initial_wall" "$CACHE_DIR/current_wallpaper.png" 2>/dev/null || trueif command -v awww &>/dev/null; thenpgrep -x awww-daemon > /dev/null 2>&1 || { awww-daemon & sleep 0.5; }awww img "$initial_wall" --transition-type grow --transition-duration 1 2>/dev/null || truefi# Verify key outputs existlocal key_outputs=("$CONFIG_DIR/waybar/style.css" "$CONFIG_DIR/hypr/colors.lua" "$CONFIG_DIR/swaync/style.css")local all_exist=truefor f in "${key_outputs[@]}"; doif [ ! -f "$f" ]; thenwarn " Missing: $f"all_exist=falsefidoneif [ "$all_exist" = true ]; thenok "Theme generated from $(basename "$initial_wall")"elsewarn "Theme generation had issues - some output files missing"warn "Run manually: matugen image \"$initial_wall\" --config \"$CONFIG_DIR/matugen/config.toml\""fi}install_systemd_services() {log "Installing systemd services..."mkdir -p "${XDG_CONFIG_HOME:-$HOME/.config}/systemd/user"cp "$DOTFILES_DIR/systemd/user/matugen-cache-daemon.service" \"${XDG_CONFIG_HOME:-$HOME/.config}/systemd/user/matugen-cache-daemon.service"systemctl --user daemon-reload 2>/dev/null || truesystemctl --user enable --now matugen-cache-daemon.service 2>/dev/null || trueok "matugen-cache-daemon service started"if command -v bluetoothctl &>/dev/null; thensudo rfkill unblock bluetooth 2>/dev/null || truesudo systemctl daemon-reload 2>/dev/null || trueif systemctl list-unit-files bluetooth.service &>/dev/null; thensudo systemctl enable --now bluetooth.service || warn "Could not enable bluetooth.service"ok "Bluetooth service enabled"elsewarn "bluetooth.service unit not found — try reinstalling bluez"fifi# Enable NetworkManager so WiFi reliably auto-connects on bootif systemctl list-unit-files NetworkManager.service &>/dev/null; thensudo systemctl enable --now NetworkManager.service 2>/dev/null || \warn "Could not enable NetworkManager.service — WiFi may not auto-connect"sudo systemctl start NetworkManager.service 2>/dev/null || trueok "NetworkManager service enabled"elsewarn "NetworkManager.service unit not found — WiFi TUI (impala) requires it"fi}install_cargo_tools() {command -v cargo &>/dev/null || { warn "cargo not found, install rust to enable cargo-based tool installation"; return 0; }if ! command -v bluetui &>/dev/null; thenlog "Installing bluetui via cargo..."cargo install bluetui && ok " bluetui installed" || warn " bluetui install failed"fiif ! command -v impala &>/dev/null; thenlog "Installing impala via cargo..."cargo install impala && ok " impala installed" || warn " impala install failed"fiif ! command -v matugen &>/dev/null; thenlog "Installing matugen via cargo..."cargo install matugen && ok " matugen installed" || warn " matugen install failed"fi}verify_critical_tools() {log "Verifying critical tools..."local missing=()local tools=("brightnessctl:brightnessctl:for display backlight control""matugen:matugen:for theme generation from wallpapers""swaync:swaync:notification daemon""notify-send:libnotify:for desktop notifications""bluetoothctl:bluez-utils:Bluetooth control""playerctl:playerctl:media player control""rofi:rofi:application launcher and menus""waybar:waybar:status bar""kitty:kitty:terminal emulator")for entry in "${tools[@]}"; dolocal bin="${entry%%:*}"local pkg="${entry#*:}"; pkg="${pkg%%:*}"local desc="${entry##*:}"if ! command -v "$bin" &>/dev/null; thenmissing+=("$pkg ($desc)")fidoneif command -v bluetui &>/dev/null; thenok " bluetui found - Bluetooth TUI available"elsewarn " bluetui not found - tui-bluetooth.sh will fall back to bluetoothctl"warn " Install: paru -S bluetui (Arch) or cargo install bluetui"fiif command -v impala &>/dev/null; thenok " impala found - WiFi TUI available"elsewarn " impala not found - tui-wifi.sh will fall back to nmtui"warn " Install: paru -S impala (Arch) or cargo install impala"fiif [ ${#missing[@]} -gt 0 ]; thenwarn "Missing critical tools:"for m in "${missing[@]}"; dowarn " - $m"donewarn "Install missing packages manually for full functionality."elseok "All critical tools present"fi}verify_swaync_running() {log "Verifying notification daemon..."if pgrep -x swaync > /dev/null 2>&1; thenok "swaync is running"elsewarn "swaync is not running. Attempting to start..."swaync &>/dev/null &sleep 1if pgrep -x swaync > /dev/null 2>&1; thenok "swaync started successfully"elsewarn "Could not start swaync. Notifications will not work."warn "After logging into Hyprland, run: swaync &"warn "Or add 'swaync' to your Hyprland autostart."fifilocal dbus_running=falseif command -v busctl &>/dev/null; thenif busctl list 2>/dev/null | grep -q "org.freedesktop.Notifications"; thendbus_running=truefielif command -v dbus-send &>/dev/null; thenif dbus-send --session --dest=org.freedesktop.DBus --type=method_call --print-reply \/org/freedesktop/DBus org.freedesktop.DBus.ListNames 2>/dev/null | \grep -q "org.freedesktop.Notifications"; thendbus_running=truefifiif [ "$dbus_running" = true ]; thenok "Notification D-Bus service is registered"elsewarn "No notification daemon registered on D-Bus"warn "After swaync starts, run: notify-send test"fi}verify_theme_outputs() {log "Verifying theme output files..."local outputs=("waybar/style.css""waybar/config.jsonc""swaync/style.css""hypr/colors.lua")local all_ok=truefor f in "${outputs[@]}"; doif [ -f "$CONFIG_DIR/$f" ]; thenok " $f exists"elsewarn " $f missing - theme may not be applied"all_ok=falsefidoneif [ "$all_ok" = false ]; thenwarn "Some theme files are missing. Run: matugen image ~/Pictures/Wallpapers/<image> --config $CONFIG_DIR/matugen/config.toml"fi}# ═══════════════════════════════════════════════════════════════# MAIN# ═══════════════════════════════════════════════════════════════echo ""echo -e "${CYAN}╔══════════════════════════════════╗${NC}"echo -e "${CYAN}║ bitzdots — Auto Installer ║${NC}"echo -e "${CYAN}╚══════════════════════════════════╝${NC}"echo ""SKIP_DEPS=falsewhile [[ $# -gt 0 ]]; docase "$1" in--skip-deps)SKIP_DEPS=true;;--help|-h)echo "Usage: $0 [OPTIONS]"echo ""echo " --skip-deps Skip installation of dependencies"echo " --help, -h Show this help"exit 0;;*)warn "Unknown option: $1";;esacshiftdoneif $SKIP_DEPS; thenlog "Skipping dependency installation (--skip-deps set)"elseinstall_depsficleanup_wallustsetup_wallpaperssetup_cachemkdir -p "$HOME/Pictures/Screenshots/Fullscreen" "$HOME/Pictures/Screenshots/Freeform" 2>/dev/null || trueinstall_nerd_fontinstall_scriptslink_dotfilesmake_executablesetup_runcatfix_pathsadd_keybindgenerate_initial_themeinstall_systemd_services# Add user to video group for backlight accessif command -v brightnessctl &>/dev/null; thenif ! groups "$USER" | grep -q video; thensudo usermod -aG video "$USER" 2>/dev/null || truewarn "Added $USER to 'video' group — log out and back in for brightnessctl to work"fifiif ! $SKIP_DEPS; theninstall_cargo_toolsfi# Force dark theme for GTK4 apps (Nautilus, etc.)if command -v gsettings &>/dev/null; thengsettings set org.gnome.desktop.interface color-scheme prefer-dark 2>/dev/null || truefi# Prepare Chromium policy directories for BrowserThemeColor enterprise policylog "Setting up Chromium browser theme policy directories..."for policy_dir in /etc/brave/policies/managed \/etc/opt/chrome/policies/managed \/etc/chromium/policies/managed \/etc/opt/edge/policies/managed \/etc/vivaldi/policies/managed \/etc/thorium/policies/managed; dosudo mkdir -p "$policy_dir" 2>/dev/null || truesudo chmod 777 "$policy_dir" 2>/dev/null || truedonerm -f "$HOME/.local/share/applications/brave-browser.desktop" \"$HOME/.local/share/applications/chromium.desktop" \"$HOME/.local/share/applications/google-chrome.desktop" 2>/dev/null || true# Restart xdg-desktop-portal-hyprland to prevent CPU loop (known 1.4.x issue)if systemctl --user is-active xdg-desktop-portal-hyprland &>/dev/null; thensystemctl --user restart xdg-desktop-portal-hyprland 2>/dev/null || trueok "xdg-desktop-portal-hyprland restarted (fixes CPU loop)"fiverify_critical_toolsverify_swaync_runningverify_theme_outputs# Restart waybar and swaync to pick up new configsif pgrep -x waybar > /dev/null 2>&1; thenlog "Restarting waybar..."pkill -x waybar 2>/dev/null || truesleep 0.3waybar &>/dev/null &fiif pgrep -x swaync > /dev/null 2>&1; thenlog "Reloading swaync config..."swaync-client -R 2>/dev/null || trueswaync-client --reload-css 2>/dev/null || truefi# Start workspace monitor if Hyprland is runningif pgrep -x Hyprland > /dev/null 2>&1; thenif ! pgrep -f workspace-monitor > /dev/null 2>&1; then"$CONFIG_DIR/waybar/scripts/workspace-monitor.sh" &fifiecho ""echo -e "${GREEN}╔══════════════════════════════════╗${NC}"echo -e "${GREEN}║ Installation complete! ║${NC}"echo -e "${GREEN}╚══════════════════════════════════╝${NC}"echo ""echo -e " ${YELLOW}Usage:${NC}"echo " SUPER+SHIFT+W — Open wallpaper picker"echo ""echo -e " ${YELLOW}Or run manually:${NC}"echo " ~/.config/matugen/wallpaper-select.sh"echo ""echo -e " ${YELLOW}Notes:${NC}"echo " • Add wallpapers to $WALL_DIR/"echo " • Add live wallpapers (.mp4/.webm/.gif) to $WALL_DIR/live/"echo " • To manually generate theme: matugen image <wallpaper>"echo " • Install mpvpaper for live wallpaper support"echo ""