#!/bin/bash # ============================================================================= # OMARCHY ZSH SETUP SCRIPT v2.1 # ============================================================================= # GitHub: https://github.com/marcogll/scripts_mg # Instalación: bash <(curl -fsSL https://raw.githubusercontent.com/marcogll/scripts_mg/main/omarchy_zsh_setup/omarchy-setup.sh) # ============================================================================= set -e # Colores RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' CYAN='\033[0;36m' NC='\033[0m' BOLD='\033[1m' TOTAL_STEPS=19 CURRENT_STEP=0 ZEROTIER_NETWORK="" KEYRING_PASSWORD="" NEEDS_REBOOT=false # Logging LOG_FILE="$HOME/omarchy-setup.log" ERROR_LOG="$HOME/omarchy-errors.log" # ============================================================================= # LOGGING # ============================================================================= setup_logging() { # Crear archivos de log : > "$LOG_FILE" : > "$ERROR_LOG" # Redirigir stdout y stderr exec > >(tee -a "$LOG_FILE") exec 2> >(tee -a "$ERROR_LOG" >&2) log "===================================================================" log "OMARCHY SETUP v2.1 - $(date '+%Y-%m-%d %H:%M:%S')" log "===================================================================" } log() { echo "[$(date '+%H:%M:%S')] $*" | tee -a "$LOG_FILE" } log_error() { echo "[$(date '+%H:%M:%S')] ERROR: $*" | tee -a "$ERROR_LOG" >&2 } # ============================================================================= # FUNCIONES AUXILIARES # ============================================================================= print_header() { clear echo -e "${CYAN}╔════════════════════════════════════════════════════════════════╗${NC}" echo -e "${CYAN}║${NC}${BOLD} OMARCHY ZSH SETUP v2.1 - Setup Completo${NC} ${CYAN}║${NC}" echo -e "${CYAN}╚════════════════════════════════════════════════════════════════╝${NC}" echo "" echo -e "${CYAN}Logs:${NC} $LOG_FILE" echo -e "${CYAN}Errores:${NC} $ERROR_LOG" echo "" } progress_bar() { local step=$1 local total=$2 local text=$3 local percent=$((step * 100 / total)) local completed=$((step * 50 / total)) local remaining=$((50 - completed)) printf "\r${BLUE}[${NC}" printf "%${completed}s" | tr ' ' '█' printf "%${remaining}s" | tr ' ' '░' printf "${BLUE}]${NC} ${percent}%% - ${text}" } step() { CURRENT_STEP=$((CURRENT_STEP + 1)) echo "" log "STEP ${CURRENT_STEP}/${TOTAL_STEPS}: $1" echo -e "${GREEN}[${CURRENT_STEP}/${TOTAL_STEPS}]${NC} ${BOLD}$1${NC}" progress_bar $CURRENT_STEP $TOTAL_STEPS "$1" echo "" } success() { echo -e "${GREEN}✓${NC} $1" log "SUCCESS: $1" } warning() { echo -e "${YELLOW}⚠${NC} $1" log "WARNING: $1" } error() { echo -e "${RED}✗${NC} $1" log_error "$1" } info() { echo -e "${CYAN}ℹ${NC} $1" log "INFO: $1" } ask_yes_no() { local prompt="$1" local default="${2:-y}" if [[ "$default" == "y" ]]; then prompt="$prompt [Y/n]: " else prompt="$prompt [y/N]: " fi while true; do read -p "$(echo -e ${YELLOW}$prompt${NC})" response response=${response:-$default} case $response in [Yy]* ) log "USER: $prompt -> YES"; return 0;; [Nn]* ) log "USER: $prompt -> NO"; return 1;; * ) echo "Por favor responde sí (y) o no (n).";; esac done } check_installed() { local pkg=$1 pacman -Q "$pkg" &> /dev/null } # ============================================================================= # VERIFICACIONES # ============================================================================= check_requirements() { if [ "$EUID" -eq 0 ]; then error "No ejecutes este script como root" exit 1 fi if ! command -v pacman &> /dev/null; then error "Este script es solo para Arch Linux / Omarchy" exit 1 fi success "Sistema compatible detectado" } # ============================================================================= # INSTALACIÓN DE PAQUETES # ============================================================================= install_packages() { step "Instalando paquetes base" local packages=( "zsh" "git" "curl" "wget" "python" "python-pip" "python-virtualenv" "nodejs" "npm" "go" "docker" "docker-compose" "yt-dlp" "ffmpeg" "playerctl" "brightnessctl" "pamixer" "lsof" "net-tools" "gnome-keyring" "libsecret" "seahorse" "cups" "cups-pdf" "system-config-printer" "gutenprint" "foomatic-db-gutenprint-ppds" "tumbler" "ffmpegthumbnailer" "poppler-glib" "gdk-pixbuf2" "gst-plugins-good" "gst-plugins-bad" "gst-plugins-ugly" "gst-libav" "libheif" "webp-pixbuf-loader" "fastfetch" "htop" "btop" "tree" "unzip" "p7zip" "unrar" ) info "Actualizando base de datos de paquetes..." sudo pacman -Sy --noconfirm local to_install=() local total=${#packages[@]} local current=0 for pkg in "${packages[@]}"; do current=$((current + 1)) if ! check_installed "$pkg"; then to_install+=("$pkg") fi printf "\r Verificando paquetes... [%d/%d]" $current $total done echo "" if [ ${#to_install[@]} -eq 0 ]; then success "Todos los paquetes ya están instalados" return fi info "Instalando ${#to_install[@]} paquetes nuevos..." log "Paquetes a instalar: ${to_install[*]}" if sudo pacman -S --noconfirm --needed "${to_install[@]}"; then success "Paquetes instalados: ${#to_install[@]}" else error "Fallo al instalar algunos paquetes" log_error "Paquetes que fallaron: revisar log de pacman" fi } install_yay() { step "Instalando yay (AUR helper)" if command -v yay &> /dev/null; then success "yay ya está instalado" return fi info "Clonando yay desde AUR..." cd /tmp rm -rf yay git clone https://aur.archlinux.org/yay.git --quiet cd yay info "Compilando yay..." if makepkg -si --noconfirm --nocheck; then cd ~ success "yay instalado" else cd ~ error "Fallo al instalar yay" exit 1 fi } install_oh_my_posh() { step "Instalando Oh My Posh" if command -v oh-my-posh &> /dev/null; then success "Oh My Posh ya está instalado" return fi info "Intentando instalar oh-my-posh-bin desde AUR..." log "Método 1: Instalación desde AUR" if yay -S --noconfirm oh-my-posh-bin 2>&1 | tee -a "$LOG_FILE"; then success "Oh My Posh instalado desde AUR" return fi warning "Fallo instalación desde AUR, intentando con script oficial..." log "Método 2: Script de instalación oficial" info "Descargando e instalando Oh My Posh..." if curl -s https://ohmyposh.dev/install.sh | bash -s 2>&1 | tee -a "$LOG_FILE"; then # Agregar al PATH si se instaló en ~/.local/bin export PATH="$HOME/.local/bin:$PATH" if command -v oh-my-posh &> /dev/null; then success "Oh My Posh instalado con script oficial" # Asegurar que esté en el PATH permanentemente if ! grep -q ".local/bin" "$HOME/.zshrc" 2>/dev/null; then info "Agregando ~/.local/bin al PATH..." fi else error "Fallo al instalar Oh My Posh" warning "Continuando sin Oh My Posh (puedes instalarlo después)" fi else error "Fallo al instalar Oh My Posh con script oficial" warning "Continuando sin Oh My Posh" fi } install_google_chrome() { step "Instalando Google Chrome" for chromium_pkg in omarchy-chromium chromium; do if check_installed "$chromium_pkg"; then info "Removiendo $chromium_pkg..." sudo pacman -Rns --noconfirm "$chromium_pkg" 2>/dev/null || true fi done if command -v google-chrome-stable &> /dev/null; then success "Google Chrome ya está instalado" else info "Instalando Google Chrome desde AUR..." if yay -S --noconfirm google-chrome; then success "Google Chrome instalado" else error "Fallo al instalar Google Chrome" fi fi } install_localsend() { step "Instalando LocalSend" if command -v localsend_app &> /dev/null; then success "LocalSend ya está instalado" return fi info "Instalando LocalSend desde AUR..." if yay -S --noconfirm localsend-bin; then success "LocalSend instalado" info "Abre LocalSend desde el menú de aplicaciones" else error "Fallo al instalar LocalSend" fi } install_emoji_launcher() { step "Instalando Emoji Launcher" local packages_needed=("rofi" "wl-clipboard") local to_install=() for pkg in "${packages_needed[@]}"; do if ! check_installed "$pkg"; then to_install+=("$pkg") fi done if [ ${#to_install[@]} -gt 0 ]; then info "Instalando dependencias..." sudo pacman -S --noconfirm --needed "${to_install[@]}" fi if ! command -v rofimoji &> /dev/null; then info "Instalando rofimoji..." yay -S --noconfirm rofimoji fi if [ -f "$HOME/.config/hypr/bindings.conf" ]; then if ! grep -q "rofimoji" "$HOME/.config/hypr/bindings.conf"; then cat >> "$HOME/.config/hypr/bindings.conf" << 'EOF' # Emoji Launcher - SUPER+PERIOD bindd = SUPER, PERIOD, Emoji Picker, exec, rofimoji EOF fi fi success "Emoji launcher instalado (SUPER+.)" } install_epson_drivers() { step "Instalando drivers Epson L4150" info "Instalando drivers Epson..." yay -S --noconfirm epson-inkjet-printer-escpr epson-inkjet-printer-escpr2 info "Instalando Epson Scan..." yay -S --noconfirm epsonscan2 || warning "epsonscan2 no disponible" info "Habilitando CUPS..." sudo systemctl enable --now cups.service sudo systemctl enable --now cups-browsed.service 2>/dev/null || true sudo usermod -aG lp "$USER" NEEDS_REBOOT=true success "Drivers Epson instalados" info "Configura en: http://localhost:631" } install_zerotier() { step "Instalando ZeroTier One" if command -v zerotier-cli &> /dev/null; then success "ZeroTier ya está instalado" else info "Instalando zerotier-one..." yay -S --noconfirm zerotier-one success "ZeroTier instalado" fi info "Habilitando servicio..." sudo systemctl enable --now zerotier-one.service NEEDS_REBOOT=true echo "" echo -e "${CYAN}════════════════════════════════════════════════════════${NC}" echo -e "${BOLD}Configuración de ZeroTier Network${NC}" echo -e "${CYAN}════════════════════════════════════════════════════════${NC}" echo "" if ask_yes_no "¿Conectarse a tu red ZeroTier?" "y"; then read -p "$(echo -e ${YELLOW}Network ID: ${NC})" ZEROTIER_NETWORK log "ZeroTier Network ID: $ZEROTIER_NETWORK" if [ ! -z "$ZEROTIER_NETWORK" ]; then info "Conectando..." sudo zerotier-cli join "$ZEROTIER_NETWORK" success "Solicitud enviada" warning "Autoriza en: https://my.zerotier.com" echo "" sudo zerotier-cli listnetworks fi fi } configure_gnome_keyring() { step "Configurando GNOME Keyring" echo "" echo -e "${CYAN}════════════════════════════════════════════════════════${NC}" echo -e "${BOLD}Configuración de GNOME Keyring${NC}" echo -e "${CYAN}════════════════════════════════════════════════════════${NC}" echo "" info "Guarda contraseñas de Git, VS Code, etc." echo "" if ask_yes_no "¿Configurar ahora?" "y"; then echo "" echo -e "${YELLOW}Opciones:${NC}" echo " 1. Sin contraseña (conveniente)" echo " 2. Contraseña de usuario (recomendado)" echo " 3. Personalizada" echo "" read -p "$(echo -e ${YELLOW}Selecciona [1/2/3]: ${NC})" keyring_option log "Keyring option: $keyring_option" case "$keyring_option" in 2) echo "" info "Ingresa tu contraseña de usuario:" read -s KEYRING_PASSWORD echo "" ;; 3) echo "" read -sp "$(echo -e ${YELLOW}Nueva contraseña: ${NC})" KEYRING_PASSWORD echo "" read -sp "$(echo -e ${YELLOW}Confirmar: ${NC})" keyring_confirm echo "" [ "$KEYRING_PASSWORD" != "$keyring_confirm" ] && KEYRING_PASSWORD="" ;; *) KEYRING_PASSWORD="" ;; esac info "Configurando PAM..." if ! grep -q "pam_gnome_keyring" /etc/pam.d/login 2>/dev/null; then echo "auth optional pam_gnome_keyring.so" | sudo tee -a /etc/pam.d/login > /dev/null echo "session optional pam_gnome_keyring.so auto_start" | sudo tee -a /etc/pam.d/login > /dev/null fi [ -f /etc/pam.d/sddm ] && ! grep -q "pam_gnome_keyring" /etc/pam.d/sddm && { echo "auth optional pam_gnome_keyring.so" | sudo tee -a /etc/pam.d/sddm > /dev/null echo "session optional pam_gnome_keyring.so auto_start" | sudo tee -a /etc/pam.d/sddm > /dev/null } eval $(gnome-keyring-daemon --start --components=pkcs11,secrets,ssh 2>/dev/null) export SSH_AUTH_SOCK GPG_AGENT_INFO GNOME_KEYRING_CONTROL GNOME_KEYRING_PID success "GNOME Keyring configurado" fi } # ============================================================================= # ZSH # ============================================================================= install_oh_my_zsh() { step "Instalando Oh My Zsh" if [ -d "$HOME/.oh-my-zsh" ]; then success "Oh My Zsh ya está instalado" return fi info "Descargando..." sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" "" --unattended success "Oh My Zsh instalado" } install_zsh_plugins() { step "Instalando plugins de Zsh" local ZSH_CUSTOM="${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}" [ ! -d "$ZSH_CUSTOM/plugins/zsh-autosuggestions" ] && \ git clone https://github.com/zsh-users/zsh-autosuggestions "$ZSH_CUSTOM/plugins/zsh-autosuggestions" --quiet [ ! -d "$ZSH_CUSTOM/plugins/zsh-syntax-highlighting" ] && \ git clone https://github.com/zsh-users/zsh-syntax-highlighting.git "$ZSH_CUSTOM/plugins/zsh-syntax-highlighting" --quiet success "Plugins instalados" } install_oh_my_posh_theme() { step "Configurando tema Oh My Posh" mkdir -p ~/.poshthemes curl -fsSL https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/catppuccin.omp.json \ -o ~/.poshthemes/catppuccin.omp.json success "Tema Catppuccin listo" } create_zshrc() { step "Creando configuración Zsh" [ -f "$HOME/.zshrc" ] && cp "$HOME/.zshrc" "$HOME/.zshrc.backup.$(date +%Y%m%d_%H%M%S)" cat > "$HOME/.zshrc" << 'ZSHRC_EOF' # ============================================================================= # CONFIGURACIÓN ZSH - OMARCHY v2.1 # ============================================================================= # --- PATH -------------------------------------------------------------------- typeset -U PATH path path=( $HOME/.local/bin $HOME/bin $HOME/.npm-global/bin $HOME/AppImages $HOME/go/bin $path ) # --- Oh My Zsh --------------------------------------------------------------- export ZSH="$HOME/.oh-my-zsh" ZSH_THEME="" plugins=( git sudo history colorize docker docker-compose npm node python pip golang copypath copyfile ) export ZSH_DISABLE_COMPFIX=true zstyle ':completion::complete:*' use-cache on zstyle ':completion::complete:*' cache-path "$HOME/.zcompcache" zstyle ':completion:*' matcher-list 'm:{a-z}={A-Za-z}' zstyle ':completion:*' list-colors "${(s.:.)LS_COLORS}" zstyle ':completion:*' menu select [ -r "$ZSH/oh-my-zsh.sh" ] && source "$ZSH/oh-my-zsh.sh" [ -r "${ZSH_CUSTOM:-$ZSH/custom}/plugins/zsh-autosuggestions/zsh-autosuggestions.zsh" ] && \ source "${ZSH_CUSTOM:-$ZSH/custom}/plugins/zsh-autosuggestions/zsh-autosuggestions.zsh" [ -r "${ZSH_CUSTOM:-$ZSH/custom}/plugins/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh" ] && \ source "${ZSH_CUSTOM:-$ZSH/custom}/plugins/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh" # --- Oh My Posh -------------------------------------------------------------- if command -v oh-my-posh >/dev/null 2>&1; then if [ -f ~/.poshthemes/catppuccin.omp.json ]; then eval "$(oh-my-posh init zsh --config ~/.poshthemes/catppuccin.omp.json)" else eval "$(oh-my-posh init zsh)" fi fi # --- Go ---------------------------------------------------------------------- export GOPATH="$HOME/go" export GOBIN="$GOPATH/bin" # --- NVM --------------------------------------------------------------------- export NVM_DIR="$HOME/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" [ -s "$NVM_DIR/bash_completion" ] && . "$NVM_DIR/bash_completion" # --- Python ------------------------------------------------------------------ alias pip='pip3' alias python='python3' venv() { case "$1" in create) python -m venv .venv && echo "✅ Entorno creado" ;; on|activate) [ -f ".venv/bin/activate" ] && . .venv/bin/activate && echo "🟢 Activado" || echo "❌ No encontrado" ;; off|deactivate) deactivate 2>/dev/null && echo "🔴 Desactivado" || echo "🤷 No activo" ;; *) echo "Uso: venv [create|on|off]" ;; esac } # --- Aliases ----------------------------------------------------------------- alias cls='clear' alias ll='ls -alF' alias la='ls -A' alias l='ls -CF' alias ..='cd ..' alias ...='cd ../..' alias ....='cd ../../..' # System info alias ff='fastfetch' alias nf='fastfetch' # Arch alias pacu='sudo pacman -Syu' alias paci='sudo pacman -S' alias pacr='sudo pacman -Rns' alias pacs='pacman -Ss' alias yayu='yay -Syu' alias yayi='yay -S' # Git alias gs='git status' alias ga='git add' alias gc='git commit' alias gcm='git commit -m' alias gp='git push' alias gl='git pull' alias gd='git diff' alias gb='git branch' alias gco='git checkout' alias gcb='git checkout -b' alias glog='git log --oneline --graph --decorate' gac(){ git add . && git commit -m "$1"; } # Docker docker compose version >/dev/null 2>&1 && alias dc='docker compose' || alias dc='docker-compose' alias d='docker' alias dps='docker ps -a' alias di='docker images' alias dex='docker exec -it' alias dlog='docker logs -f' # NPM alias nrs='npm run start' alias nrd='npm run dev' alias nrb='npm run build' alias nrt='npm run test' alias ni='npm install' alias nid='npm install --save-dev' alias nig='npm install -g' # Python alias py='python' alias pir='pip install -r requirements.txt' alias pipi='pip install' alias pipf='pip freeze > requirements.txt' # ZeroTier alias zt='sudo zerotier-cli' alias ztstatus='sudo zerotier-cli listnetworks' alias ztinfo='sudo zerotier-cli info' alias clima='curl wttr.in/Saltillo' # --- Funciones --------------------------------------------------------------- mkcd(){ mkdir -p "$1" && cd "$1"; } extract(){ [ ! -f "$1" ] && echo "No es un archivo" && return 1 case "$1" in *.tar.bz2) tar xjf "$1" ;; *.tar.gz) tar xzf "$1" ;; *.bz2) bunzip2 "$1" ;; *.rar) unrar e "$1" ;; *.gz) gunzip "$1" ;; *.tar) tar xf "$1" ;; *.tbz2) tar xjf "$1" ;; *.tgz) tar xzf "$1" ;; *.zip) unzip "$1" ;; *.Z) uncompress "$1" ;; *.7z) 7z x "$1" ;; *) echo "No se puede extraer '$1'" ;; esac } killport(){ [ $# -eq 0 ] && echo "Uso: killport " && return 1 local pid=$(lsof -ti:"$1" 2>/dev/null) [ -n "$pid" ] && kill -9 "$pid" && echo "✅ Eliminado" || echo "🤷 No encontrado" } serve(){ python -m http.server "${1:-8000}"; } # --- yt-dlp MEJORADO --------------------------------------------------------- export YTDLP_DIR="$HOME/Videos/YouTube" mkdir -p "$YTDLP_DIR"/{Music,Videos} ytm() { case "$1" in -h|--help|'') echo "🎵 ytm - MP3 320kbps" echo "Ejemplos:" echo " ytm https://youtu.be/..." echo " ytm 'nombre canción'" return 0 ;; esac local out="$YTDLP_DIR/Music/%(title).180s.%(ext)s" local opts=( --extract-audio --audio-format mp3 --audio-quality 320K --embed-metadata --embed-thumbnail --convert-thumbnails jpg --no-playlist --retries 10 --fragment-retries 10 --user-agent "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36" --extractor-args "youtube:player_client=android,web" --progress --newline -o "$out" ) if [[ "$1" == http* ]]; then echo "📥 Descargando audio..." yt-dlp "${opts[@]}" "$@" else echo "🔍 Buscando: $*" yt-dlp "${opts[@]}" "ytsearch1:$*" fi [ $? -eq 0 ] && echo "✅ En: $YTDLP_DIR/Music/" } ytv() { case "$1" in -h|--help|'') echo "🎬 ytv [calidad]" echo "Calidades: 1080, 720, 480 (default: best)" return 0 ;; esac local quality="${2:-best}" local out="$YTDLP_DIR/Videos/%(title).180s.%(ext)s" local fmt case "$quality" in 1080) fmt='bv*[height<=1080][ext=mp4]+ba/b[height<=1080]' ;; 720) fmt='bv*[height<=720][ext=mp4]+ba/b[height<=720]' ;; 480) fmt='bv*[height<=480][ext=mp4]+ba/b[height<=480]' ;; *) fmt='bv*[ext=mp4]+ba/b[ext=mp4]/b' ;; esac local opts=( -f "$fmt" --embed-metadata --embed-thumbnail --embed-subs --sub-langs "es.*,en.*" --convert-thumbnails jpg --no-playlist --retries 10 --fragment-retries 10 --user-agent "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36" --extractor-args "youtube:player_client=android,web" --progress --newline -o "$out" ) if [[ "$1" == http* ]]; then echo "📥 Descargando video..." yt-dlp "${opts[@]}" "$1" else echo "🔍 Buscando: $1" yt-dlp "${opts[@]}" "ytsearch1:$1" fi [ $? -eq 0 ] && echo "✅ En: $YTDLP_DIR/Videos/" } ytls() { echo "🎵 Music:" ls -1t "$YTDLP_DIR/Music" 2>/dev/null | head -5 | sed 's/^/ /' || echo " (vacío)" echo "" echo "🎬 Videos:" ls -1t "$YTDLP_DIR/Videos" 2>/dev/null | head -5 | sed 's/^/ /' || echo " (vacío)" } # --- GNOME Keyring ----------------------------------------------------------- if [ -n "$DESKTOP_SESSION" ]; then if ! pgrep -u "$USER" gnome-keyring-daemon > /dev/null 2>&1; then eval $(gnome-keyring-daemon --start --components=pkcs11,secrets,ssh 2>/dev/null) fi export SSH_AUTH_SOCK GPG_AGENT_INFO GNOME_KEYRING_CONTROL GNOME_KEYRING_PID fi # --- Historial --------------------------------------------------------------- HISTSIZE=100000 SAVEHIST=100000 HISTFILE=~/.zsh_history setopt APPEND_HISTORY SHARE_HISTORY HIST_IGNORE_DUPS HIST_IGNORE_ALL_DUPS HIST_IGNORE_SPACE AUTO_CD EXTENDED_GLOB stty -ixon 2>/dev/null export LESS='-R' # --- Funciones externas ------------------------------------------------------ [ -d "$HOME/.zsh_functions" ] || mkdir -p "$HOME/.zsh_functions" for func_file in "$HOME/.zsh_functions"/*.zsh(N); do source "$func_file" done # --- Local ------------------------------------------------------------------- [ -f ~/.zshrc.local ] && source ~/.zshrc.local ZSHRC_EOF success ".zshrc creado" } # ============================================================================= # CONFIGURACIÓN # ============================================================================= configure_permissions() { step "Configurando permisos" sudo usermod -aG docker,video,input,lp "$USER" sudo chmod +s /usr/bin/brightnessctl 2>/dev/null || true sudo tee /etc/udev/rules.d/90-backlight.rules > /dev/null << 'EOF' ACTION=="add", SUBSYSTEM=="backlight", RUN+="/bin/chgrp video /sys/class/backlight/%k/brightness" ACTION=="add", SUBSYSTEM=="backlight", RUN+="/bin/chmod g+w /sys/class/backlight/%k/brightness" EOF sudo udevadm control --reload-rules 2>/dev/null || true success "Permisos configurados" } configure_git() { step "Configurando Git" git config --global user.name &> /dev/null && success "Git ya configurado" && return echo "" if ask_yes_no "¿Configurar Git?" "y"; then read -p "$(echo -e ${YELLOW}Nombre: ${NC})" git_name read -p "$(echo -e ${YELLOW}Email: ${NC})" git_email log "Git config: $git_name <$git_email>" git config --global user.name "$git_name" git config --global user.email "$git_email" git config --global credential.helper libsecret git config --global init.defaultBranch main success "Git configurado" fi } configure_npm() { step "Configurando NPM" mkdir -p ~/.npm-global npm config set prefix '~/.npm-global' success "NPM configurado" } setup_directories() { step "Creando directorios" mkdir -p ~/AppImages ~/Videos/YouTube/{Music,Videos} ~/Projects ~/.zsh_functions ~/go/{bin,src,pkg} gsettings set org.gnome.nautilus.preferences show-image-thumbnails 'always' 2>/dev/null || true success "Directorios creados" } set_default_shell() { step "Configurando Zsh" [ "$SHELL" == "$(which zsh)" ] && success "Zsh ya es el shell" && return chsh -s $(which zsh) NEEDS_REBOOT=true success "Zsh configurado" } # ============================================================================= # MAIN # ============================================================================= main() { setup_logging print_header echo -e "${BOLD}Este script instalará:${NC}" echo "" echo " • Zsh + Oh My Zsh + Oh My Posh (Catppuccin)" echo " • Google Chrome (remueve omarchy-chromium)" echo " • LocalSend (compartir archivos)" echo " • Drivers Epson L4150 + Scan" echo " • ZeroTier One" echo " • Emoji Launcher (SUPER+.)" echo " • GNOME Keyring" echo " • Go, Git, Docker, Node, Python, yt-dlp" echo "" ask_yes_no "¿Continuar?" "y" || { info "Cancelado"; exit 0; } echo "" check_requirements install_packages install_yay install_oh_my_posh install_google_chrome install_localsend install_emoji_launcher install_epson_drivers install_zerotier configure_gnome_keyring install_oh_my_zsh install_zsh_plugins install_oh_my_posh_theme create_zshrc configure_permissions configure_git configure_npm setup_directories set_default_shell echo "" log "===================================================================" log "INSTALACIÓN COMPLETADA - $(date '+%Y-%m-%d %H:%M:%S')" log "===================================================================" echo -e "${GREEN}✓✓✓ Instalación completada ✓✓✓${NC}" echo "" echo -e "${CYAN}📋 Logs guardados en:${NC}" echo -e " ${BOLD}$LOG_FILE${NC}" echo -e " ${BOLD}$ERROR_LOG${NC}" echo "" if [ "$NEEDS_REBOOT" = true ]; then echo -e "${YELLOW}╔════════════════════════════════════════════╗${NC}" echo -e "${YELLOW}║${NC} ${BOLD}REINICIO REQUERIDO${NC} ${YELLOW}║${NC}" echo -e "${YELLOW}╚════════════════════════════════════════════╝${NC}" echo "" echo -e "${CYAN}Cambios que requieren reinicio:${NC}" echo " • Grupos de usuario (docker, lp, video)" echo " • Servicios (CUPS, ZeroTier)" echo " • Shell predeterminado (Zsh)" echo "" if ask_yes_no "¿Reiniciar ahora?" "y"; then echo "" info "Reiniciando en 3 segundos..." sleep 3 sudo reboot else warning "Recuerda reiniciar manualmente" fi else echo -e "${CYAN}Próximos pasos:${NC}" echo " 1. Cierra esta terminal" echo " 2. Abre una nueva" echo " 3. Ejecuta: source ~/.zshrc" fi echo "" [ ! -z "$ZEROTIER_NETWORK" ] && echo -e "${YELLOW}⚠${NC} Autoriza en: https://my.zerotier.com" echo "" } main "$@"