Team Ai
Apppublic

ptrindade/linuxoptimizerpro

sourceHugging Faceupdated 1y agoView on Hugging Face
0likes
index.html573 linesDownload Raw Back to root
1#!/usr/bin/env python32"""3Linux System Optimizer - GUI Application v2.14==============================================5Uma aplicação gráfica para diagnosticar, limpar, atualizar e otimizar sistemas Linux.6Baseada nos comandos do documento 'comandos linux.rd'7 8Versão 2.1: Novo esquema de cores moderno9Autor: Sistema de Otimização Linux10Data: Outubro 202511"""12 13import tkinter as tk14from tkinter import ttk, scrolledtext, messagebox, simpledialog15import subprocess16import threading17import os18import sys19from datetime import datetime20 21 22class LinuxOptimizer:23    def __init__(self, root):24        self.root = root25        self.root.title("Linux System Optimizer v2.1")26        self.root.geometry("1400x900")27        self.root.minsize(1000, 700)28        29        # Verificar se está a correr como root30        self.is_root = os.geteuid() == 031        32        # Configurar estilo33        self.setup_styles()34        35        # Configurar interface principal36        self.create_main_interface()37        38        # Configurar scroll global do rato39        self.setup_global_mousewheel()40        41        # Mostrar aviso se não for root (desativado para teste)42        # if not self.is_root:43        #     self.show_sudo_warning()44    45    def setup_global_mousewheel(self):46        """Configurar scroll do rato globalmente - VERSÃO MELHORADA"""47        def _on_mousewheel(event):48            # Encontrar o widget atual sob o cursor49            widget = event.widget50            attempts = 051            while widget and attempts < 10:  # Limitar tentativas52                # Se encontrar um Canvas, fazer scroll nele53                if isinstance(widget, tk.Canvas):54                    try:55                        # Verificar se o canvas tem scroll vertical56                        if widget.cget('yscrollcommand'):57                            widget.yview_scroll(int(-1*(event.delta/120)), "units")58                            return "break"59                    except:60                        pass61                # Se encontrar um Text widget com scrollbar62                elif hasattr(widget, 'yview_scroll'):63                    try:64                        widget.yview_scroll(int(-1*(event.delta/120)), "units")65                        return "break"66                    except:67                        pass68                widget = widget.master69                attempts += 170        71        # Bind global do scroll mais agressivo72        self.root.bind_all("<MouseWheel>", _on_mousewheel)73    74    def font_exists(self, font_name):75        """Verificar se uma fonte específica existe no sistema"""76        try:77            import tkinter.font as tkFont78            available_fonts = tkFont.families()79            return font_name in available_fonts80        except:81            return False82    83    def setup_styles(self):84        """Configurar estilos do tkinter"""85        style = ttk.Style()86        style.theme_use('clam')87        88        # Esquema de cores moderno - Dark Theme com acentos vibrantes89        self.colors = {90            'primary': '#0f172a',       # Slate 900 - Azul muito escuro91            'secondary': '#1e293b',     # Slate 800 - Azul escuro médio92            'accent': '#7c3aed',        # Violet 600 - Roxo vibrante93            'accent_light': '#a855f7',  # Purple 500 - Roxo claro94            'success': '#059669',       # Emerald 600 - Verde esmeralda95            'warning': '#ea580c',       # Orange 600 - Laranja vibrante96            'danger': '#dc2626',        # Red 600 - Vermelho forte97            'info': '#0284c7',          # Sky 600 - Azul informativo98            'dark': '#020617',          # Slate 950 - Preto suave99            'medium': '#334155',        # Slate 700 - Cinza azulado100            'light': '#e2e8f0',        # Slate 200 - Cinza muito claro101            'surface': '#f1f5f9',      # Slate 100 - Superfície clara102            'text_light': '#f8fafc',   # Slate 50 - Texto claro103            'text_dark': '#0f172a',    # Slate 900 - Texto escuro104            'border': '#64748b',       # Slate 500 - Bordas105            'hover_primary': '#1e40af', # Blue 700 - Hover azul106            'hover_accent': '#8b5cf6'   # Violet 500 - Hover roxo107        }108        109        # Configurar estilos personalizados com novo esquema110        style.configure('Title.TLabel', 111                       font=('Segoe UI', 20, 'bold'), 112                       foreground=self.colors['text_light'],113                       background=self.colors['primary'])114        115        style.configure('Subtitle.TLabel', 116                       font=('Segoe UI', 12), 117                       foreground='#cbd5e1',  # Slate 300 - texto suave118                       background=self.colors['primary'])119        120        # Estilo para o notebook (abas) com gradiente121        style.configure('TNotebook', 122                       background=self.colors['secondary'],123                       borderwidth=0,124                       tabmargins=[2, 5, 2, 0])125        126        style.configure('TNotebook.Tab', 127                       font=('Segoe UI', 11, 'bold'),128                       padding=(25, 15),129                       background=self.colors['medium'],130                       foreground='#94a3b8')  # Slate 400131        132        style.map('TNotebook.Tab',133                 background=[('selected', self.colors['accent']),134                           ('active', self.colors['accent_light'])],135                 foreground=[('selected', self.colors['text_light']),136                           ('active', self.colors['text_light'])])137        138        # Configurar cor de fundo da janela principal139        self.root.configure(bg=self.colors['primary'])140    141    # Função setup_global_mousewheel removida (estava duplicada)142    143    def create_main_interface(self):144        """Criar a interface principal com abas"""145        146        # Frame principal147        main_frame = tk.Frame(self.root, bg=self.colors['primary'])148        main_frame.pack(fill=tk.BOTH, expand=True, padx=15, pady=15)149        150        # Header com gradiente visual151        header_frame = tk.Frame(main_frame, bg=self.colors['primary'], height=80)152        header_frame.pack(fill=tk.X, pady=(0, 20))153        header_frame.pack_propagate(False)154        155        # Título da aplicação156        title_label = ttk.Label(header_frame, text="🐧 Linux System Optimizer v2.1", 157                               style='Title.TLabel')158        title_label.pack(pady=(15, 5))159        160        # Status do utilizador161        status_text = "🔴 A correr como utilizador normal (alguns comandos requerem sudo)" if not self.is_root else "🟢 A correr como root - acesso completo"162        status_label = ttk.Label(header_frame, text=status_text, style='Subtitle.TLabel')163        status_label.pack(pady=(0, 10))164        165        # Container principal com PanedWindow para redimensionamento166        content_frame = tk.Frame(main_frame, bg=self.colors['primary'])167        content_frame.pack(fill=tk.BOTH, expand=True)168        169        # PanedWindow para permitir redimensionar entre abas e output170        self.paned_window = tk.PanedWindow(content_frame, 171                                          orient=tk.VERTICAL,172                                          bg=self.colors['primary'],173                                          sashwidth=8,174                                          sashrelief='raised')175        self.paned_window.pack(fill=tk.BOTH, expand=True)176        177        # Frame superior para as abas178        tabs_frame = tk.Frame(self.paned_window, bg=self.colors['primary'])179        self.paned_window.add(tabs_frame, minsize=300)180        181        # Criar notebook para abas182        self.notebook = ttk.Notebook(tabs_frame)183        self.notebook.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)184        185        # Criar abas186        self.create_diagnostic_tab()187        self.create_cleanup_tab()188        self.create_update_tab()189        self.create_optimization_tab()190        191        # Frame inferior para o output (redimensionável)192        output_container = tk.Frame(self.paned_window, bg=self.colors['primary'])193        self.paned_window.add(output_container, minsize=200)194        195        # Área de output196        self.create_output_area(output_container)197    198    def create_scrollable_tab(self, notebook, tab_name, icon):199        """Criar uma aba com scroll funcional"""200        # Frame principal da aba com cor atualizada201        main_tab_frame = tk.Frame(notebook, bg=self.colors['surface'])202        notebook.add(main_tab_frame, text=f"{icon} {tab_name}")203        204        # Canvas e scrollbar com cores atualizadas205        canvas = tk.Canvas(main_tab_frame, bg=self.colors['surface'], 206                          highlightthickness=0, borderwidth=0)207        scrollbar = ttk.Scrollbar(main_tab_frame, orient="vertical", command=canvas.yview)208        scrollable_frame = tk.Frame(canvas, bg=self.colors['surface'])209        210        # Configurar scroll211        scrollable_frame.bind(212            "<Configure>",213            lambda e: canvas.configure(scrollregion=canvas.bbox("all"))214        )215        216        canvas.create_window((0, 0), window=scrollable_frame, anchor="nw")217        canvas.configure(yscrollcommand=scrollbar.set)218        219        # O scroll global já está configurado - não precisamos duplicar aqui220        221        # Pack elementos222        canvas.pack(side="left", fill="both", expand=True, padx=(10, 0), pady=10)223        scrollbar.pack(side="right", fill="y", pady=10, padx=(0, 10))224        225        return scrollable_frame226    227    def create_diagnostic_tab(self):228        """Criar aba de Diagnóstico"""229        scrollable_frame = self.create_scrollable_tab(self.notebook, "Diagnóstico", "🔍")230        231        # Seção: Informações do Sistema232        self.create_section(scrollable_frame, "💻 Informações do Sistema", [233            ("Ver informações da CPU", "lscpu", False),234            ("Ver informações de memória", "free -h", False),235            ("Ver informações de hardware", "sudo lshw -short", True),236            ("Ver temperatura (se disponível)", "sensors", False),237        ])238        239        # Seção: Uso de Disco240        self.create_section(scrollable_frame, "💾 Análise de Disco", [241            ("Ver espaço em disco", "df -h", False),242            ("Ver dispositivos de bloco", "lsblk", False),243            ("Analisar diretórios grandes (raiz)", "sudo du -h / 2>/dev/null | sort -rh | head -10", True),244            ("Analisar diretório home", "du -h ~/ | sort -rh | head -20", False),245            ("Encontrar ficheiros grandes (+100MB)", "find / -type f -size +100M 2>/dev/null | head -20", False),246        ])247        248        # Seção: Processos e Performance249        self.create_section(scrollable_frame, "⚡ Processos e Performance", [250            ("Processos que mais consomem CPU", "ps aux --sort=-%cpu | head -11", False),251            ("Processos que mais consomem Memória", "ps aux --sort=-%mem | head -11", False),252            ("Abrir htop (monitor interativo)", "htop", False),253            ("Ver tempo de boot", "systemd-analyze", False),254            ("Serviços mais lentos no boot", "systemd-analyze blame", False),255        ])256        257        # Seção: Rede e Sistema258        self.create_section(scrollable_frame, "🌐 Rede e Sistema", [259            ("Ver conexões de rede ativas", "ss -tuln", False),260            ("Ver informações de rede", "ip addr show", False),261            ("Ver serviços em execução", "systemctl list-units --type=service --state=running", False),262            ("Ver serviços falhados", "systemctl --failed", False),263        ])264    265    def create_cleanup_tab(self):266        """Criar aba de Limpeza"""267        scrollable_frame = self.create_scrollable_tab(self.notebook, "Limpeza", "🧹")268        269        # Seção: Cache APT270        self.create_section(scrollable_frame, "📦 Cache de Pacotes APT", [271            ("Ver tamanho do cache APT", "du -sh /var/cache/apt/archives/", False),272            ("Limpeza conservadora (autoclean)", "sudo apt autoclean", True),273            ("Limpeza completa (clean)", "sudo apt clean", True),274            ("Remover pacotes órfãos", "sudo apt autoremove --purge", True),275        ])276        277        # Seção: Logs do Sistema278        self.create_section(scrollable_frame, "📄 Logs do Sistema", [279            ("Ver tamanho dos logs", "sudo du -h /var/log/ | sort -rh | head -10", True),280            ("Limpar logs (manter 3 dias)", "sudo journalctl --vacuum-time=3d", True),281            ("Limitar logs (máx 100MB)", "sudo journalctl --vacuum-size=100M", True),282            ("Esvaziar syslog", "sudo truncate -s 0 /var/log/syslog", True),283        ])284        285        # Seção: Ficheiros Temporários286        self.create_section(scrollable_frame, "🗂️ Ficheiros Temporários", [287            ("Ver tamanho do /tmp", "du -sh /tmp/", False),288            ("Limpar cache do utilizador", "rm -rf ~/.cache/*", False),289            ("Limpar thumbnails", "rm -rf ~/.thumbnails/*", False),290            ("Limpar lixeira", "rm -rf ~/.local/share/Trash/*", False),291            ("Limpar /tmp (cuidado!)", "sudo rm -rf /tmp/*", True),292        ])293        294        # Seção: Snaps295        self.create_section(scrollable_frame, "📱 Gestão de Snaps", [296            ("Listar snaps instalados", "snap list", False),297            ("Ver política de retenção", "snap get system refresh.retain", False),298            ("Limpar snaps (manual)", "# Use: sudo snap remove <nome> --revision <num>", False),299        ])300    301    def create_update_tab(self):302        """Criar aba de Atualizações"""303        scrollable_frame = self.create_scrollable_tab(self.notebook, "Atualizações", "🔄")304        305        # Seção: Atualizações de Sistema306        self.create_section(scrollable_frame, "🔧 Sistema APT", [307            ("Atualizar lista de pacotes", "sudo apt update", True),308            ("Fazer upgrade de pacotes", "sudo apt upgrade", True),309            ("Fazer dist-upgrade", "sudo apt dist-upgrade", True),310            ("Ver pacotes que podem ser atualizados", "apt list --upgradable", False),311        ])312        313        # Seção: Snaps314        self.create_section(scrollable_frame, "📱 Snaps", [315            ("Atualizar todos os snaps", "sudo snap refresh", True),316            ("Ver atualizações disponíveis", "snap refresh --list", False),317        ])318        319        # Seção: Verificação de Integridade320        self.create_section(scrollable_frame, "🔍 Verificação de Integridade", [321            ("Verificar integridade dos pacotes", "sudo dpkg --configure -a", True),322            ("Verificar dependências", "sudo apt-get check", True),323            ("Corrigir dependências quebradas", "sudo apt --fix-broken install", True),324        ])325        326        # Seção: Kernels327        self.create_section(scrollable_frame, "⚙️ Gestão de Kernels", [328            ("Ver kernels instalados", "dpkg -l | grep linux-image", False),329            ("Remover kernels antigos", "sudo apt autoremove --purge", True),330        ])331    332    def create_optimization_tab(self):333        """Criar aba de Otimização"""334        scrollable_frame = self.create_scrollable_tab(self.notebook, "Otimização", "⚡")335        336        # Seção: Análise de Performance337        self.create_section(scrollable_frame, "📊 Análise de Performance", [338            ("Análise crítica do boot", "systemd-analyze critical-chain", False),339            ("Monitorizar I/O de disco", "sudo iotop", True),340            ("Estatísticas de I/O", "iostat -x 1 5", False),341        ])342        343        # Seção: Gestão de Serviços344        self.create_section(scrollable_frame, "🔧 Gestão de Serviços", [345            ("Ver serviços habilitados", "systemctl list-unit-files --type=service --state=enabled", False),346            ("Desativar serviço", "# Use: sudo systemctl disable --now <serviço>", False),347            ("Mascarar serviço", "# Use: sudo systemctl mask <serviço>", False),348        ])349        350        # Seção: Otimizações do Sistema351        self.create_section(scrollable_frame, "⚙️ Sistema", [352            ("Atualizar base de dados locate", "sudo updatedb", True),353            ("Atualizar cache de man pages", "sudo mandb", True),354            ("Ver uso de swap", "swapon --show", False),355            ("Verificar saúde do SSD", "sudo smartctl -a /dev/sda", True),356        ])357        358        # Seção: Aplicações de Arranque359        self.create_section(scrollable_frame, "🚀 Arranque", [360            ("Ver aplicações de arranque", "ls ~/.config/autostart/", False),361            ("Editar aplicações de arranque", "# Use um editor para ~/.config/autostart/", False),362        ])363    364    def create_section(self, parent, title, commands):365        """Criar uma seção com título e comandos - CÓPIA EXATA DO TESTE FUNCIONAL"""366        # Frame da seção - SIMPLIFICAR367        section_frame = tk.LabelFrame(parent, text=f"  {title}  ", padx=20, pady=15,368                                    bg=self.colors['light'], fg=self.colors['text_dark'],369                                    font=('Segoe UI', 12, 'bold'))370        section_frame.pack(fill=tk.X, padx=20, pady=20)371        372        # Frame único para todos os botões373        buttons_frame = tk.Frame(section_frame, bg=self.colors['light'])374        buttons_frame.pack(fill=tk.X, pady=5)375        376        for desc, cmd, needs_sudo in commands:377            # Cores378            if needs_sudo:379                color = self.colors['danger']380            else:381                color = self.colors['accent']382            383            # Criar botão384            btn = tk.Button(buttons_frame, 385                         text=desc,386                         bg=color, fg='white',387                         font=('Arial', 11, 'bold'),388                         padx=10, pady=5,389                         command=lambda c=cmd, s=needs_sudo: self.run_command(c, s))390            391            # Pack horizontal com espaçamento392            btn.pack(side=tk.LEFT, padx=5, pady=5, fill=tk.X, expand=True)393    394    def create_output_area(self, parent):395        """Criar área de output redimensionável"""396        # Frame do output com estilo moderno397        output_frame = tk.LabelFrame(parent, 398                                   text="  📋 Resultado dos Comandos (Redimensionável)  ",399                                   bg=self.colors['light'],400                                   fg=self.colors['text_dark'],401                                   font=('Segoe UI', 11, 'bold'),402                                   padx=10, pady=10,403                                   borderwidth=2,404                                   relief='solid')405        output_frame.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)406        407        # Frame para o texto e scrollbar personalizada408        text_frame = tk.Frame(output_frame, bg=self.colors['light'])409        text_frame.pack(fill=tk.BOTH, expand=True, pady=(0, 10))410        411        # Terminal com novo esquema de cores412        self.output_text = scrolledtext.ScrolledText(text_frame, 413                                                   bg=self.colors['dark'], 414                                                   fg='#06ffa5',  # Verde neon mais moderno415                                                   font=('JetBrains Mono', 10) if self.font_exists('JetBrains Mono') else ('Consolas', 10),416                                                   insertbackground='#06ffa5',417                                                   selectbackground=self.colors['accent'],418                                                   selectforeground=self.colors['text_light'],419                                                   borderwidth=0,420                                                   highlightthickness=2,421                                                   highlightcolor=self.colors['accent'],422                                                   highlightbackground=self.colors['border'],423                                                   padx=15, pady=12,424                                                   wrap=tk.WORD)425        self.output_text.pack(fill=tk.BOTH, expand=True)426        427        # Botões de controlo com design moderno428        control_frame = tk.Frame(output_frame, bg=self.colors['light'])429        control_frame.pack(fill=tk.X)430        431        # Botões com novo design432        clear_btn = tk.Button(control_frame, 433                             text="🗑️ Limpar Output",434                             font=('Segoe UI', 10, 'bold'),435                             bg=self.colors['warning'],436                             fg=self.colors['text_light'],437                             activebackground='#c2410c',  # Orange 700438                             activeforeground=self.colors['text_light'],439                             borderwidth=0,440                             relief='flat',441                             padx=25, pady=10,442                             cursor='hand2',443                             command=self.clear_output)444        clear_btn.pack(side=tk.LEFT, padx=(0, 15))445        446        # Botão guardar com cor info447        save_btn = tk.Button(control_frame, 448                            text="💾 Guardar Log",449                            font=('Segoe UI', 10, 'bold'),450                            bg=self.colors['info'],451                            fg=self.colors['text_light'],452                            activebackground='#0369a1',  # Sky 700453                            activeforeground=self.colors['text_light'],454                            borderwidth=0,455                            relief='flat',456                            padx=25, pady=10,457                            cursor='hand2',458                            command=self.save_log)459        save_btn.pack(side=tk.LEFT)460        461        # Efeitos hover melhorados462        def create_hover_effect(button, hover_color, normal_color):463            def on_enter(event):464                button.configure(bg=hover_color)465            def on_leave(event):466                button.configure(bg=normal_color)467            button.bind("<Enter>", on_enter)468            button.bind("<Leave>", on_leave)469        470        create_hover_effect(clear_btn, '#c2410c', self.colors['warning'])  # Orange 700471        create_hover_effect(save_btn, '#0369a1', self.colors['info'])      # Sky 700472    473    def run_command(self, command, needs_sudo):474        """Executar comando em thread separada"""475        if needs_sudo and not self.is_root:476            # Pedir confirmação para comandos sudo477            if not messagebox.askyesno("Confirmação", 478                                     f"Este comando requer privilégios de administrador:\n\n{command}\n\nContinuar?"):479                return480        481        # Executar em thread separada482        thread = threading.Thread(target=self._execute_command, args=(command,))483        thread.daemon = True484        thread.start()485    486    def _execute_command(self, command):487        """Executar comando e mostrar resultado"""488        timestamp = datetime.now().strftime("%H:%M:%S")489        self.append_output(f"\n[{timestamp}] Executando: {command}\n" + "="*60 + "\n")490        491        try:492            # Executar comando493            if command.startswith('#'):494                # Comentário, não executar495                self.append_output("ℹ️ Este é um comando informativo/exemplo.\n")496                return497            498            if command.startswith('sudo') and not self.is_root:499                # Tentar executar com pkexec se disponível500                alt_command = command.replace('sudo ', 'pkexec ')501                try:502                    result = subprocess.run(alt_command, shell=True, capture_output=True, 503                                          text=True, timeout=30)504                except:505                    # Fallback para sudo normal506                    result = subprocess.run(command, shell=True, capture_output=True, 507                                          text=True, timeout=30)508            else:509                result = subprocess.run(command, shell=True, capture_output=True, 510                                      text=True, timeout=30)511            512            # Mostrar resultado513            if result.stdout:514                self.append_output(result.stdout)515            if result.stderr:516                self.append_output(f"⚠️ Avisos/Erros:\n{result.stderr}")517            518            if result.returncode == 0:519                self.append_output("\n✅ Comando executado com sucesso!\n")520            else:521                self.append_output(f"\n❌ Comando falhou com código {result.returncode}\n")522                523        except subprocess.TimeoutExpired:524            self.append_output("\n⏱️ Comando excedeu tempo limite (30s)\n")525        except Exception as e:526            self.append_output(f"\n❌ Erro ao executar comando: {str(e)}\n")527        528        self.append_output("\n" + "="*60 + "\n")529    530    def append_output(self, text):531        """Adicionar texto ao output de forma thread-safe"""532        def update():533            self.output_text.insert(tk.END, text)534            self.output_text.see(tk.END)535        536        self.root.after(0, update)537    538    def clear_output(self):539        """Limpar área de output"""540        self.output_text.delete(1.0, tk.END)541    542    def save_log(self):543        """Guardar log em ficheiro"""544        content = self.output_text.get(1.0, tk.END)545        if not content.strip():546            messagebox.showwarning("Aviso", "Não há conteúdo para guardar.")547            return548        549        filename = f"linux_optimizer_log_{datetime.now().strftime('%Y%m%d_%H%M%S')}.txt"550        try:551            with open(filename, 'w') as f:552                f.write(content)553            messagebox.showinfo("Sucesso", f"Log guardado como {filename}")554        except Exception as e:555            messagebox.showerror("Erro", f"Erro ao guardar log: {str(e)}")556    557    def show_sudo_warning(self):558        """Mostrar aviso sobre permissões"""559        messagebox.showinfo("Informação", 560                          "A aplicação está a correr como utilizador normal.\n\n"561                          "Alguns comandos (marcados a vermelho) requerem privilégios de administrador.\n\n"562                          "Para melhor experiência, execute com:\nsudo python3 linux_optimizer.py")563 564 565def main():566    """Função principal"""567    root = tk.Tk()568    app = LinuxOptimizer(root)569    root.mainloop()570 571 572if __name__ == "__main__":573    main()