diff --git a/debianito.sh b/debianito.sh index ae2a47b..4e4f323 100644 --- a/debianito.sh +++ b/debianito.sh @@ -32,6 +32,8 @@ source "${MODULES_DIR}/repos.sh" [ -f "${MODULES_DIR}/rescue.sh" ] && source "${MODULES_DIR}/rescue.sh" [ -f "${MODULES_DIR}/swap.sh" ] && source "${MODULES_DIR}/swap.sh" [ -f "${MODULES_DIR}/desktop_display.sh" ] && source "${MODULES_DIR}/desktop_display.sh" +[ -f "${MODULES_DIR}/system/system_prefs.sh" ] && source "${MODULES_DIR}/system/system_prefs.sh" +[ -f "${MODULES_DIR}/system/audio.sh" ] && source "${MODULES_DIR}/system/audio.sh" # ── Bullseye-specific modules (loaded only on Debian 11) ── if [ -d "${MODULES_DIR}/bullseye" ]; then @@ -60,24 +62,26 @@ main_menu() { $TUI_ALTO $TUI_ANCHO $TUI_ALTO_LISTA \ "1" "System Information" \ "2" "User Privileges & Feedback" \ - "3" "Configure Repositories" \ - "4" "Firmware, Wireless & Bluetooth" \ - "5" "Graphics Drivers & Mesa Stack" \ - "6" "Kernel" \ - "7" "Gaming Setup" \ - "8" "ZRAM" \ - "9" "Swap Management" \ - "10" "Install Programs and Software" \ - "11" "Boot Rescue + GRUB" \ - "12" "Desktop & Display" \ - "13" "Exit") + "3" "System Preferences" \ + "4" "Configure Repositories" \ + "5" "Firmware, Wireless & Bluetooth" \ + "6" "Graphics Drivers & Mesa Stack" \ + "7" "Kernel" \ + "8" "Gaming Setup" \ + "9" "ZRAM" \ + "10" "Swap Management" \ + "11" "Install Programs and Software" \ + "12" "Boot Rescue + GRUB" \ + "13" "Desktop & Display" \ + "14" "Exit") clear case "$choice" in 1) _show_sysinfo ;; 2) config_sudo || true ;; - 3) + 3) _system_preferences_menu ;; + 4) if [ "$DEBIAN_VERSION" = "11" ] && type configure_repos_bullseye &>/dev/null; then configure_repos_bullseye || true else @@ -85,14 +89,14 @@ main_menu() { fi STATE_REFRESHED=true ;; - 4) + 5) if [ "$DEBIAN_VERSION" = "11" ] && type install_firmware_bullseye &>/dev/null; then install_firmware_bullseye || true else install_firmware || true fi ;; - 5) + 6) local gpu_sub gpu_sub=$(_menu "Graphics Drivers" "" 12 50 2 \ "1" "Radeon/Intel Mesa" \ @@ -105,8 +109,8 @@ main_menu() { esac STATE_REFRESHED=true ;; - 6) show_kernel_menu || true ;; - 7) + 7) show_kernel_menu || true ;; + 8) if [ "$DEBIAN_VERSION" = "11" ] && type install_gaming_bullseye &>/dev/null; then install_gaming_bullseye || true else @@ -114,18 +118,18 @@ main_menu() { fi STATE_REFRESHED=true ;; - 8) zram_menu || true ;; - 9) manage_swap || true; STATE_REFRESHED=true ;; - 10) + 9) zram_menu || true ;; + 10) manage_swap || true; STATE_REFRESHED=true ;; + 11) if [ "$DEBIAN_VERSION" = "11" ] && type install_extras_bullseye &>/dev/null; then install_extras_bullseye || true else install_extras || true fi ;; - 11) rescue_boot || true ;; - 12) manage_desktop_display || true ;; - 13) echo "Exiting."; exit 0 ;; + 12) rescue_boot || true ;; + 13) manage_desktop_display || true ;; + 14) echo "Exiting."; exit 0 ;; esac if $STATE_REFRESHED; then refresh_system_state diff --git a/modules/desktop_display.sh b/modules/desktop_display.sh index 7b65e23..396731c 100644 --- a/modules/desktop_display.sh +++ b/modules/desktop_display.sh @@ -11,13 +11,130 @@ manage_desktop_display() { [ -z "$choice" ] && break clear case "$choice" in - 1) _msg "Coming Soon" "Desktop Environment management will be available in a future update." 10 60 ;; + 1) desktop_environment_menu ;; 2) display_manager_menu ;; 3) break ;; esac done } +desktop_environment_menu() { + while true; do + local -a env_items=() + env_items+=("1" "XFCE") + env_items+=("2" "Back") + # Future desktop environments: add "2" "GNOME", "3" "KDE", ... here + # and a matching case below calling its own menu (e.g. gnome_menu). + local choice + choice=$(_menu "Desktop Environment" \ + "Select a desktop environment:" $TUI_ALTO $TUI_ANCHO $TUI_ALTO_LISTA \ + "${env_items[@]}") + [ -z "$choice" ] && break + clear + case "$choice" in + 1) xfce_menu ;; + 2) break ;; + esac + done +} + +xfce_menu() { + while true; do + local -a xf_items=() + xf_items+=("1" "XFCE (Full Meta Package)") + xf_items+=("2" "XFCE (Minimal Core)") + [ "$DEBIAN_VERSION" = "13" ] && xf_items+=("3" "XFCE Wayland (Experimental — labwc)") + xf_items+=("4" "XFCE Custom (Choose packages)") + xf_items+=("5" "Back") + local choice + choice=$(_menu "XFCE" \ + "Select an option:" $TUI_ALTO $TUI_ANCHO $TUI_ALTO_LISTA \ + "${xf_items[@]}") + [ -z "$choice" ] && break + clear + case "$choice" in + 1) _install_xfce_full ;; + 2) _install_xfce_minimal ;; + 3) _install_xfce_wayland ;; + 4) _install_xfce_custom ;; + 5) break ;; + esac + done +} + +_install_xfce_full() { + _run_cmd "XFCE Full" "sudo apt install -y xfce4 xfce4-goodies xfce4-power-manager" \ + "Installing XFCE (Full Meta Package)..." + _xfce_polkit_rules +} + +_install_xfce_minimal() { + _run_cmd "XFCE Minimal" "sudo apt install -y xfce4" \ + "Installing XFCE (Minimal Core)..." + _xfce_polkit_rules +} + +_install_xfce_wayland() { + _run_cmd "XFCE Wayland" "sudo apt install -y xfce4 labwc" \ + "Installing XFCE + labwc (Wayland, experimental)..." + _msg "XFCE Wayland" "labwc is EXPERIMENTAL on XFCE 4.20.\n\nAfter reboot, select the Wayland session\nfrom the login screen." 12 65 + _xfce_polkit_rules +} + +_install_xfce_custom() { + local -a items=() + for pkg in thunar xfdesktop4 xfwm4 xfce4-panel xfce4-terminal \ + xfce4-screenshooter ristretto mousepad xfce4-session \ + xfce4-settings xfce4-power-manager; do + items+=("$pkg" "$pkg" "$(_state "$pkg")") + done + local choices + choices=$(_checklist "XFCE Custom" \ + "Select the XFCE packages to install:" $TUI_ALTO $TUI_ANCHO $TUI_ALTO_LISTA \ + "${items[@]}") + [ -z "$choices" ] && return + local cleaned + cleaned=$(echo "$choices" | tr -d '"') + [ -z "$cleaned" ] && return + _run_cmd "XFCE Custom" "sudo apt install -y $cleaned" \ + "Installing selected XFCE packages..." + _xfce_polkit_rules +} + +_xfce_polkit_rules() { + is_installed xfce4-power-manager || return 0 + + local rules_dir="/etc/polkit-1/rules.d" + sudo mkdir -p "$rules_dir" + + cat <<'EOF' | sudo tee "$rules_dir/85-suspend.rules" >/dev/null +polkit.addRule(function(action, subject) { + if (action.id == "org.freedesktop.login1.suspend" && + subject.isInGroup("users")) { + return polkit.Result.YES; + } +}); +EOF + cat <<'EOF' | sudo tee "$rules_dir/89-backlight.rules" >/dev/null +polkit.addRule(function(action, subject) { + if (action.id == "org.freedesktop.upower.backlight" && + subject.isInGroup("backlight")) { + return polkit.Result.YES; + } +}); +EOF + + if ! getent group backlight >/dev/null 2>&1; then + sudo groupadd --system backlight || true + fi + local de_user="${SUDO_USER:-$USER}" + if [ -n "$de_user" ] && ! id -nG "$de_user" 2>/dev/null | grep -qw backlight; then + sudo usermod -aG backlight "$de_user" || true + fi + sudo systemctl restart polkit.service 2>/dev/null || true + echo -e "${GREEN}Polkit rules installed (suspend + backlight). User '${de_user}' added to 'backlight' group.${NC}" +} + display_manager_menu() { while true; do local -a dm_items=() diff --git a/modules/extras.sh b/modules/extras.sh index 053ab85..b6707b9 100644 --- a/modules/extras.sh +++ b/modules/extras.sh @@ -43,8 +43,7 @@ install_extras() { "11" "Office & Productivity" \ "12" "System Tools" \ "13" "Fetch / System Info" \ - "14" "Audio & Sound" \ - "15" "Back to main menu") + "14" "Back to main menu") [ -z "$cat_choice" ] && return clear @@ -64,8 +63,7 @@ install_extras() { 11) _cat_office ;; 12) _cat_general ;; 13) _cat_fetch ;; - 14) _cat_audio ;; - 15) return ;; + 14) return ;; esac clear done diff --git a/modules/extras/internet/internet.sh b/modules/extras/internet/internet.sh index d1179fc..707a01d 100644 --- a/modules/extras/internet/internet.sh +++ b/modules/extras/internet/internet.sh @@ -183,9 +183,24 @@ _cat_internet() { local cleaned; cleaned=$(echo "$choices" | tr -d '"') - if echo "$cleaned" | grep -q "firefox" && echo "$cleaned" | grep -q "firefox-esr"; then - _msg "Firefox" "You selected both Firefox (Mozilla) and Firefox ESR.\nPlease choose only one Firefox variant." 10 60 - return + local has_firefox=false + local has_firefox_esr=false + for _p in $cleaned; do + [ "$_p" = "firefox" ] && has_firefox=true + [ "$_p" = "firefox-esr" ] && has_firefox_esr=true + done + + if $has_firefox && $has_firefox_esr; then + local fchoice + fchoice=$(_menu "Firefox" "You selected both Firefox (Mozilla) and Firefox ESR.\nWhat do you want to do?" 12 60 3 \ + "mozilla" "Remove Firefox ESR — keep Firefox" \ + "esr" "Remove Firefox — keep Firefox ESR" \ + "both" "Keep both variants") + [ -z "$fchoice" ] && return + case "$fchoice" in + mozilla) cleaned=$(printf '%s\n' $cleaned | grep -vx "firefox-esr" | tr '\n' ' ') ;; + esr) cleaned=$(printf '%s\n' $cleaned | grep -vx "firefox" | tr '\n' ' ') ;; + esac fi for pkg in $cleaned; do diff --git a/modules/gpu.sh b/modules/gpu.sh index 9776d63..5876917 100644 --- a/modules/gpu.sh +++ b/modules/gpu.sh @@ -191,12 +191,19 @@ _install_nvidia_stack() { NVIDIA_DRIVER_MODE="" - if ! _nvidia_manage_menu; then - return + if _nvidia_driver_installed; then + if ! _nvidia_manage_menu; then + return + fi fi if [ "$DEBIAN_VERSION" = "11" ]; then - install_nvidia_bullseye + if type install_nvidia_bullseye &>/dev/null; then + install_nvidia_bullseye + else + _msg "NVIDIA — Bullseye" "The Bullseye NVIDIA module is not available.\n\nNo NVIDIA driver was installed." 10 60 + NVIDIA_DRIVER_MODE="" + fi else if ! _show_nvidia_version_menu; then @@ -230,7 +237,9 @@ _install_nvidia_stack() { NVIDIA_DRIVER_MODE="" ;; blackwell) - _install_nvidia_cuda_repo + _msg "NVIDIA — Blackwell (v550)" \ + "Your Blackwell GPU is NOT supported by the official\nDebian v550 driver.\n\nPlease select v590 or v595 (NVIDIA CUDA Repo)\nin the driver menu." 14 65 + NVIDIA_DRIVER_MODE="" ;; maxwell|pascal|volta) if [ "$(is_backports_kernel)" = "true" ]; then @@ -253,7 +262,7 @@ Forcing the stable driver path." 14 70 _install_nvidia_standard fi ;; - turing|ampere|ada|blackwell) + turing|ampere|ada) _install_nvidia_standard ;; *) diff --git a/modules/gpu/nvidia_manage.sh b/modules/gpu/nvidia_manage.sh index 76c2fc5..bc5f8c1 100644 --- a/modules/gpu/nvidia_manage.sh +++ b/modules/gpu/nvidia_manage.sh @@ -1,6 +1,10 @@ #!/usr/bin/env bash # nvidia_manage.sh — NVIDIA management menu: install/change or remove +_nvidia_driver_installed() { + dpkg -l 2>/dev/null | grep -qE "^ii (nvidia-driver|nvidia-tesla-470-driver|nvidia-open|nvidia-kernel-dkms|nvidia-kernel-open-dkms|nvidia-open-kernel-dkms)" +} + _nvidia_manage_menu() { local choice choice=$(_menu "NVIDIA Driver" "Manage NVIDIA Driver" 12 70 4 \ @@ -22,7 +26,7 @@ _nvidia_manage_menu() { } _nvidia_remove() { - if ! dpkg -l 2>/dev/null | grep -qE "^ii (nvidia-driver|nvidia-tesla-470-driver|nvidia-open-kernel-dkms|nvidia-kernel-dkms)"; then + if ! _nvidia_driver_installed; then echo -e "${YELLOW}NVIDIA driver is not installed on this system.${NC}" return 0 fi @@ -33,7 +37,7 @@ _nvidia_remove() { fi echo "Removing NVIDIA driver packages..." - sudo apt purge -y nvidia-driver nvidia-kernel-dkms nvidia-open-kernel-dkms nvidia-tesla-470-driver nvidia-settings nvidia-vaapi-driver firmware-nvidia-gsp mesa-vdpau-drivers || true + sudo apt purge -y nvidia-driver nvidia-kernel-dkms nvidia-open-kernel-dkms nvidia-open nvidia-kernel-open-dkms nvidia-tesla-470-driver nvidia-settings nvidia-vaapi-driver firmware-nvidia-gsp mesa-vdpau-drivers nvidia-driver-pinning-* || true echo "Cleaning up dependencies..." sudo apt autoremove --purge -y || true diff --git a/modules/kernel.sh b/modules/kernel.sh index 585c926..00e4ec2 100644 --- a/modules/kernel.sh +++ b/modules/kernel.sh @@ -4,7 +4,7 @@ show_kernel_menu() { while true; do local items=("stable" "Install linux-image-amd64") - [ "$DEBIAN_VERSION" != "11" ] && items+=("backports" "Install from backports") + [ "$DEBIAN_VERSION" = "13" ] && items+=("backports" "Install from backports") items+=("rt" "Install linux-image-rt-amd64 (Preempt-RT)") items+=("cloud" "Install linux-image-cloud-amd64") items+=("back" "Return to main menu") diff --git a/modules/system/audio.sh b/modules/system/audio.sh new file mode 100644 index 0000000..aec8f70 --- /dev/null +++ b/modules/system/audio.sh @@ -0,0 +1,185 @@ +#!/usr/bin/env bash +# audio.sh — Audio & Sound (PipeWire, ALSA, PulseAudio tools) + +_prefs_audio_menu() { + local headless=false + _is_headless && headless=true + + local -a items=() + + local pw_label="PipeWire Audio Stack (Bluetooth Hi-Res)" + + local pw_state; pw_state=$(_state "pipewire-audio") + items+=( + "pipewire-audio" "$pw_label" "$pw_state" + ) + + local alsa_state; alsa_state=$(_state "alsa-utils") + items+=( + "alsa-utils" "ALSA Utilities (alsa-utils, alsa-ucm-conf)" "$alsa_state" + ) + + if ! $headless; then + local pavu_state; pavu_state=$(_state "pavucontrol") + items+=( + "pavucontrol" "Volume Control GUI (pavucontrol)" "$pavu_state" + ) + fi + + local pulsemixer_state; pulsemixer_state=$(_state "pulsemixer") + local playerctl_state; playerctl_state=$(_state "playerctl") + items+=( + "pulsemixer" "Terminal audio mixer (pulsemixer)" "$pulsemixer_state" + "playerctl" "Multimedia key controller (playerctl)" "$playerctl_state" + ) + + local item_count=${#items[@]} + local lista_alto=$((item_count > TUI_ALTO_LISTA ? TUI_ALTO_LISTA : item_count)) + local choices + choices=$(_checklist "Audio & Sound" "Check [*] the packages you want installed.\n" \ + $TUI_ALTO $TUI_ANCHO $lista_alto "${items[@]}") + clear + [ -z "$choices" ] && return + + local cleaned; cleaned=$(echo "$choices" | tr -d '"') + + for pkg in $cleaned; do + case $pkg in + pipewire-audio) _install_pipewire_standard ;; + alsa-utils) + if ! is_installed "alsa-utils"; then + _run_install "alsa-utils alsa-ucm-conf" + else + echo "alsa-utils already installed." + fi + ;; + pavucontrol) + if ! is_installed "pavucontrol"; then + _run_install "pavucontrol" + else + echo "pavucontrol already installed." + fi + ;; + pulsemixer) + if ! is_installed "pulsemixer"; then + _run_install "pulsemixer" + else + echo "pulsemixer already installed." + fi + ;; + playerctl) + if ! is_installed "playerctl"; then + _run_install "playerctl" + else + echo "playerctl already installed." + fi + ;; + esac + done + + echo -e "${GREEN}Audio & Sound setup complete.${NC}" +} + +_install_pipewire_standard() { + local bt_pkgs="libldacbt-abr2 libldacbt-enc2 libopenaptx0 libspa-0.2-bluetooth" + if apt-cache show libfdk-aac2t64 &>/dev/null; then + bt_pkgs+=" libfdk-aac2t64" + elif apt-cache show libfdk-aac2 &>/dev/null; then + bt_pkgs+=" libfdk-aac2" + fi + + # ── Resolve versions (needed for both installed and not-installed branches) ── + local stable_ver="" + stable_ver=$(apt-cache policy pipewire-audio 2>/dev/null | awk 'NR==3 {print $2; exit}') || true + local bpo_ver="" + if [ "$DEBIAN_VERSION" = "13" ] && [ "$(is_backports_enabled)" = "true" ]; then + bpo_ver=$(apt-cache madison pipewire-audio 2>/dev/null | \ + grep "${DEBIAN_CODENAME}-backports" | awk '{print $3}' | head -1) || true + fi + + local pkg_check="pipewire-audio" + [ "$DEBIAN_VERSION" = "11" ] && pkg_check="pipewire" + + # ── Already installed branch ── + if is_installed "$pkg_check"; then + if [ -n "$bpo_ver" ]; then + local current_ver + current_ver=$(dpkg -l "$pkg_check" 2>/dev/null | awk '/^ii/{print $3}') || true + if _confirm "PipeWire" \ + "PipeWire ${current_ver:+v${current_ver} }already installed.\n\nUpgrade to backports version v${bpo_ver}?"; then + echo "Upgrading PipeWire Audio Stack..." + echo "-> Target version: v${bpo_ver} (from ${DEBIAN_CODENAME}-backports)" + echo "-> Including Bluetooth Hi-Res codecs (LDAC, aptX, AAC)" + _run_cmd "PipeWire" \ + "sudo apt install -y --reinstall -t ${DEBIAN_CODENAME}-backports pipewire-audio $bt_pkgs" \ + "Upgrading PipeWire from backports..." + if [ "$DEBIAN_VERSION" != "11" ]; then + echo "Restarting PipeWire services..." + systemctl --user restart wireplumber pipewire pipewire-pulse 2>/dev/null || true + echo -e "${GREEN}PipeWire services restarted.${NC}" + fi + return + fi + fi + echo "$pkg_check already installed." + return + fi + + # ── Confirm dialog ── + local apt_target="" pw_ver="" pw_src="" + if [ -n "$bpo_ver" ]; then + local msg="Backports repository is enabled.\n\n" + msg+="Available versions:\n" + msg+=" - Stable: v${stable_ver:-unknown}\n" + msg+=" - Backports: v${bpo_ver}\n\n" + msg+="Install from Backports (Recommended for newer hardware)\nor from Stable (more conservative)?" + if _confirm_custom "PipeWire Install" "$msg" "Backports" "Stable" 14 70; then + apt_target="-t ${DEBIAN_CODENAME}-backports" + pw_ver="$bpo_ver" + pw_src="from ${DEBIAN_CODENAME}-backports" + else + pw_ver="$stable_ver" + fi + else + local msg="PipeWire Audio Stack (v${stable_ver:-unknown})\n" + msg+="will be installed along with Bluetooth Hi-Res\n" + msg+="codecs (LDAC, aptX, AAC).\n\n" + msg+="Continue with installation?" + if ! _confirm "PipeWire Install" "$msg" 12 65; then + echo "PipeWire installation cancelled." + return + fi + pw_ver="$stable_ver" + fi + + echo "Installing PipeWire Audio Stack..." + echo "-> Detected version: ${pw_ver:-unknown} ${pw_src:+($pw_src)}" + echo "-> Including Bluetooth Hi-Res codecs (LDAC, aptX, AAC)" + + case "$DEBIAN_VERSION" in + 11) + _run_cmd "PipeWire" \ + "sudo apt install -y pipewire libspa-0.2-bluetooth pipewire-alsa libspa-0.2-jack $bt_pkgs" \ + "Installing PipeWire (Bullseye basic mode)..." + echo -e "${GREEN}PipeWire installed (Bullseye basic mode).${NC}" + ;; + 12) + _run_cmd "PipeWire" \ + "sudo apt install -y pipewire-audio $bt_pkgs" \ + "Installing pipewire-audio meta-package (Bookworm)..." + echo -e "${GREEN}PipeWire audio stack installed.${NC}" + ;; + 13) + _run_cmd "PipeWire" \ + "sudo apt install -y $apt_target pipewire-audio $bt_pkgs" \ + "Installing pipewire-audio meta-package (Trixie)..." + echo -e "${GREEN}PipeWire audio stack installed.${NC}" + ;; + esac + + if [ "$DEBIAN_VERSION" != "11" ]; then + echo "Restarting PipeWire services..." + systemctl --user restart wireplumber pipewire pipewire-pulse 2>/dev/null || true + echo -e "${GREEN}PipeWire services restarted.${NC}" + fi +} diff --git a/modules/system/system_prefs.sh b/modules/system/system_prefs.sh new file mode 100644 index 0000000..457a607 --- /dev/null +++ b/modules/system/system_prefs.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash +# system_prefs.sh — System Preferences: time, locale, keyboard, audio + +_prefs_date_time() { + echo -e "${YELLOW}Current system date/time:${NC} $(date '+%Y-%m-%d %H:%M')" + echo -e "${YELLOW}Timezone:${NC} $(timedatectl show -p Timezone --value 2>/dev/null || echo unknown)" + + if _confirm "Timezone" "Change the system timezone (dpkg-reconfigure tzdata)?"; then + sudo env LC_ALL=C LANGUAGE=C dpkg-reconfigure tzdata || true + echo -e "${GREEN}Timezone: $(timedatectl show -p Timezone --value 2>/dev/null)${NC}" + fi + _ensure_time_synced +} + +_prefs_locale_keyboard() { + sudo env LC_ALL=C LANGUAGE=C dpkg-reconfigure locales || true + sudo env LC_ALL=C LANGUAGE=C dpkg-reconfigure keyboard-configuration || true + echo -e "${GREEN}Language, locales and keyboard configured.${NC}" +} + +_prefs_audio() { _prefs_audio_menu; } + +_system_preferences_menu() { + while true; do + local choice + choice=$(_menu "System Preferences" "Select a preference group:" \ + $TUI_ALTO $TUI_ANCHO $TUI_ALTO_LISTA \ + "1" "Date, Time & Timezone" \ + "2" "Language, Locales & Keyboard" \ + "3" "Audio & Sound Stack" \ + "4" "Back to main menu") + [ -z "$choice" ] && return + clear + case "$choice" in + 1) _prefs_date_time ;; + 2) _prefs_locale_keyboard ;; + 3) _prefs_audio ;; + 4) return ;; + esac + done +} \ No newline at end of file diff --git a/modules/utils.sh b/modules/utils.sh index a52e9aa..62cd85d 100644 --- a/modules/utils.sh +++ b/modules/utils.sh @@ -109,7 +109,7 @@ _ensure_time_synced() { if [ -n "${DISPLAY:-}" ] || [ -n "${SSH_TTY:-}" ]; then _msg "Timezone" \ "Your system timezone is not set or is set to UTC.\n\nThe script will now open the timezone\nconfiguration tool to set your local timezone." 12 60 - sudo dpkg-reconfigure tzdata +sudo env LC_ALL=C LANGUAGE=C dpkg-reconfigure tzdata || true echo -e "${GREEN}Timezone configured: $(timedatectl show -p Timezone --value 2>/dev/null)${NC}" else echo -e "${YELLOW}Timezone not set. Run 'sudo dpkg-reconfigure tzdata' later.${NC}" @@ -163,7 +163,7 @@ detect_debian_version() { # CPU and RAM info (cosmetic) # ---------------------------------- detect_cpu_ram() { - CPU_SUMMARY=$(grep -m1 'model name' /proc/cpuinfo | sed 's/.*: //') + CPU_SUMMARY=$(grep -m1 'model name' /proc/cpuinfo | sed 's/.*: //' || true) RAM_KB=$(grep MemTotal /proc/meminfo | awk '{print $2}') RAM_GB=$(awk -v kb="$RAM_KB" 'BEGIN { printf "%.2f", kb / 1048576 }') RAM_SUMMARY="${RAM_GB} GB"