Sistem Asistanı (v1.1)
# sayfalar/temizlik.py
from PyQt6.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QLabel,
QPushButton, QListWidget, QListWidgetItem,
QCheckBox, QMessageBox, QProgressBar, QTextEdit) # QTextEdit eklendi
from PyQt6.QtCore import Qt, QThread, pyqtSignal
from PyQt6.QtGui import QColor, QFont
from gorsel_araclar import SayfaBasligi, SvgIkonOlusturucu
import subprocess
import os
import shutil
import re
import time # Loglama için zaman gecikmesi ekleyebiliriz
# TaramaWorker sınıfı değişmiyor. (Yukarıdaki son haliyle aynı kalabilir.)
class TaramaWorker(QThread):
sonuc_sinyali = pyqtSignal(list)
# ... (get_dir_size, size_fmt ve run metotları aynı kalıyor)
def get_dir_size(self, path):
total = 0
try:
for dirpath, dirnames, filenames in os.walk(path):
for f in filenames:
fp = os.path.join(dirpath, f)
if not os.path.islink(fp):
total += os.path.getsize(fp)
except Exception:
pass
return total
def size_fmt(self, num):
for unit in ['B', 'KB', 'MB', 'GB']:
if abs(num) < 1024.0: return f"{num:3.1f} {unit}"
num /= 1024.0
return f"{num:.1f} TB"
def run(self):
items = []
# 1. Apt Cache (Paket Önbelleği)
try:
output = subprocess.check_output("du -sb /var/cache/apt/archives 2>/dev/null", shell=True).strip().split()[0].decode()
apt_size = int(output)
if apt_size > 10240:
items.append(("APT Paket Önbelleği", self.size_fmt(apt_size), "/var/cache/apt/archives", "apt"))
except: pass
# 2. Thumbnail Cache (~/.cache/thumbnails)
thumb_path = os.path.expanduser("~/.cache/thumbnails")
s = self.get_dir_size(thumb_path)
if s > 0:
items.append(("Küçük Resim (Thumbnail) Önbelleği", self.size_fmt(s), thumb_path, "delete_user"))
else:
items.append(("Küçük Resim (Thumbnail) Önbelleği", self.size_fmt(0), thumb_path, "delete_user_empty")) # Boş da olsa göster
# 3. Tarayıcı ve Uygulama Önbellekleri (~/.cache/mozilla, ~/.cache/google-chrome vb.)
cache_root = os.path.expanduser("~/.cache")
targets = ["mozilla", "google-chrome", "chromium", "vlc", "pip", "flatpak"]
browser_paths = []
browser_size = 0
for t in targets:
p = os.path.join(cache_root, t)
if os.path.exists(p) and os.path.isdir(p):
size = self.get_dir_size(p)
if size > 0:
browser_size += size
browser_paths.append(p)
path_str = "|".join(browser_paths)
display_path = ", ".join(t for t in targets if os.path.join(cache_root, t) in browser_paths)
if browser_size > 0:
items.append(("Tarayıcı ve Uygulama Önbellekleri", self.size_fmt(browser_size), path_str, "browser_cache"))
else:
items.append(("Tarayıcı ve Uygulama Önbellekleri", self.size_fmt(0), path_str, "browser_cache_empty")) # Boş da olsa göster
# 4. Journald (Eski Sistem Günlükleri)
try:
out = subprocess.check_output("journalctl --disk-usage 2>/dev/null", shell=True, text=True)
match = re.search(r"take up\s+([\d\.]+)\s*([KMGT]B)", out, re.IGNORECASE)
if match:
size_str = match.group(1) + " " + match.group(2)
items.append(("Eski Sistem Günlükleri (Journald)", size_str.strip(), "/var/log/journal", "journal"))
else:
items.append(("Eski Sistem Günlükleri (Journald)", self.size_fmt(0), "/var/log/journal", "journal_empty"))
except: pass
# 5. Çöp Kutusu (Kullanıcı Çöpü)
trash_root = os.path.expanduser("~/.local/share/Trash")
trash_files = os.path.join(trash_root, "files")
trash_info = os.path.join(trash_root, "info")
total_trash = 0
if os.path.exists(trash_files): total_trash += self.get_dir_size(trash_files)
if os.path.exists(trash_info): total_trash += self.get_dir_size(trash_info)
if total_trash > 0:
items.append(("Çöp Kutusu", self.size_fmt(total_trash), trash_root, "trash"))
else:
items.append(("Çöp Kutusu", self.size_fmt(0), trash_root, "trash_empty")) # Boş da olsa göster
self.sonuc_sinyali.emit(items)
class TemizlikSayfasi(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
layout = QVBoxLayout(self)
icon = SvgIkonOlusturucu.clean_ikonu("#33AADD", 32)
layout.addWidget(SayfaBasligi("Sistem Temizliği", icon))
# Bilgi
info = QLabel("Sisteminizde yer kaplayan gereksiz dosyaları tarayın ve temizleyin.")
info.setStyleSheet("color: palette(mid); margin-bottom: 10px;")
layout.addWidget(info)
# Liste
self.list_widget = QListWidget()
self.list_widget.setStyleSheet("QListWidget { font-size: 11pt; } QCheckBox { padding: 5px; }")
# Listeyi sabit bir yükseklikte tutalım
self.list_widget.setMaximumHeight(250)
layout.addWidget(self.list_widget)
# Log Konsolu
self.console_log = QTextEdit()
self.console_log.setReadOnly(True)
self.console_log.setStyleSheet("background-color: #2c3e50; color: #ecf0f1; font-family: monospace; padding: 5px;")
self.console_log.setPlaceholderText("Temizlik işlemleri burada listelenecektir...")
self.console_log.setMaximumHeight(150)
layout.addWidget(self.console_log)
# Alt Panel
h_bot = QHBoxLayout()
self.lbl_total = QLabel("Toplam Kazanç: 0 MB")
self.lbl_total.setStyleSheet("font-weight: bold; color: #2ecc71; font-size: 12pt;")
self.btn_tara = QPushButton("🔍 Tekrar Tara")
self.btn_tara.clicked.connect(self.taramayi_baslat)
self.btn_temizle = QPushButton("🧹 Seçilileri Temizle")
self.btn_temizle.setStyleSheet("background-color: #e67e22; color: white; font-weight: bold; padding: 8px 20px;")
self.btn_temizle.clicked.connect(self.temizle)
self.btn_temizle.setEnabled(False)
h_bot.addWidget(self.lbl_total)
h_bot.addStretch()
h_bot.addWidget(self.btn_tara)
h_bot.addWidget(self.btn_temizle)
layout.addLayout(h_bot)
self.taramayi_baslat()
def taramayi_baslat(self):
self.list_widget.clear()
self.console_log.clear() # Logu da temizle
self.lbl_total.setText("Taranıyor...")
self.btn_temizle.setEnabled(False)
self.btn_tara.setEnabled(False)
# Loga bildirim ekle
self.append_log("Tarama işlemi başlatılıyor...")
self.worker = TaramaWorker()
self.worker.sonuc_sinyali.connect(self.tarama_bitti)
self.worker.start()
def tarama_bitti(self, items):
self.items_data = items
self.btn_tara.setEnabled(True)
self.append_log("Tarama tamamlandı.")
total_found_size = 0.0
if not items:
self.lbl_total.setText("Sistem Temiz!")
return
self.btn_temizle.setEnabled(True)
for ad, boyut, yol, tip in items:
item = QListWidgetItem()
widget = QWidget()
h = QHBoxLayout(widget); h.setContentsMargins(5, 5, 5, 5)
chk = QCheckBox(ad)
# Boyutu sadece doluysa listede göster, boşsa gri yap
if "_empty" in tip:
chk.setChecked(False) # Boş olanları varsayılan olarak seçme
chk.setStyleSheet("font-weight: normal; color: #7f8c8d;")
lbl_size = QLabel(boyut)
lbl_size.setStyleSheet("color: #7f8c8d; font-weight: normal;")
else:
chk.setChecked(True)
chk.setStyleSheet("font-weight: bold;")
lbl_size = QLabel(boyut)
lbl_size.setStyleSheet("color: #33AADD; font-weight: bold;")
# Boyut bilgisini toplayalım (sadece dolu olanları)
if "_empty" not in tip:
try:
# Basit bir boyut toplama tahmini
val = float(boyut.split()[0].replace(',', '.'))
unit = boyut.split()[1]
if unit == 'KB': total_found_size += val / 1024.0
elif unit == 'MB': total_found_size += val
elif unit == 'GB': total_found_size += val * 1024.0
except:
pass
# Yolu sadece tarayıcı önbelleği ise kısalt
if tip.startswith("browser_cache"):
lbl_desc = QLabel(f"Önbellek Yolları: {yol.replace('|', ', ')}")
else:
lbl_desc = QLabel(f"{yol}")
lbl_desc.setStyleSheet("color: #7f8c8d; font-size: 9pt;")
v = QVBoxLayout()
v.addWidget(chk)
v.addWidget(lbl_desc)
h.addLayout(v)
h.addStretch()
h.addWidget(lbl_size)
item.setSizeHint(widget.sizeHint())
self.list_widget.addItem(item)
self.list_widget.setItemWidget(item, widget)
chk.setProperty("data_type", tip)
chk.setProperty("data_path", yol)
# Boş klasörler seçilemez olmalı
if "_empty" in tip:
chk.setEnabled(False)
self.lbl_total.setText(f"Tahmini Kazanç: {self.worker.size_fmt(total_found_size * 1024 * 1024)}")
def append_log(self, message, is_error=False):
"""Konsola log mesajı ekler."""
color = "#e74c3c" if is_error else "#2ecc71"
html_message = f'<span style="color:{color}; font-weight:bold;">[{time.strftime("%H:%M:%S")}] </span> {message}<br>'
self.console_log.insertHtml(html_message)
self.console_log.verticalScrollBar().setValue(self.console_log.verticalScrollBar().maximum())
def temizle(self):
komutlar = []
user_paths_to_delete = []
trash_mode = False
for i in range(self.list_widget.count()):
item = self.list_widget.item(i)
widget = self.list_widget.itemWidget(item)
chk = widget.findChild(QCheckBox)
# Sadece seçili ve boş olmayan (yani silinecek bir şey olan) öğeleri topla
if chk.isChecked() and "_empty" not in chk.property("data_type"):
tip = chk.property("data_type")
yol = chk.property("data_path")
if tip == "apt":
komutlar.append("apt-get clean")
self.append_log("Sistem: APT Paket Önbelleği temizleme komutu eklendi.")
elif tip == "journal":
komutlar.append("journalctl --vacuum-time=1s")
self.append_log("Sistem: Eski Sistem Günlükleri (Journald) temizleme komutu eklendi.")
elif tip == "delete_user":
user_paths_to_delete.append(yol)
self.append_log(f"Kullanıcı: Küçük Resim Önbelleği ({yol}) silinmek üzere işaretlendi.")
elif tip == "browser_cache":
browser_paths = yol.split("|")
user_paths_to_delete.extend(browser_paths)
self.append_log(f"Kullanıcı: Tarayıcı/Uygulama Önbellekleri ({len(browser_paths)} klasör) silinmek üzere işaretlendi.")
elif tip == "trash":
trash_mode = True
self.append_log("Kullanıcı: Çöp Kutusu içeriği silinmek üzere işaretlendi (Root yetkisi gerekebilir).")
if not komutlar and not user_paths_to_delete and not trash_mode:
self.append_log("Temizlenecek seçili öğe bulunamadı.", is_error=True)
return
reply = QMessageBox.question(self, "Onay", "Seçili dosyalar kalıcı olarak silinecek. Devam edilsin mi?",
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No)
if reply == QMessageBox.StandardButton.No: return
clean_success = True
self.append_log("Temizlik işlemi başlatılıyor...")
# 1. Çöp Kutusu ve Sistem Komutları (pkexec ile root yetkisi gerektirenler)
if trash_mode:
trash_root = os.path.expanduser("~/.local/share/Trash")
# rm -rf komutu, içindeki dosyaların root yetkisi olsa bile silinmesini sağlar.
trash_clean_cmd = f"rm -rf {trash_root}/files/* {trash_root}/info/*"
komutlar.append(trash_clean_cmd)
if komutlar:
full_cmd = " && ".join(komutlar)
self.append_log(f"ROOT KOMUTU ÇALIŞTIRILIYOR: {full_cmd}")
try:
# pkexec ile root yetkisi iste
subprocess.run(["pkexec", "sh", "-c", full_cmd], check=True,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
self.append_log("Sistem/Çöp Kutusu temizliği başarılı.")
except Exception as e:
QMessageBox.warning(self, "Hata", f"Sistem ve Çöp Kutusu temizliği sırasında yetki/komut hatası.")
self.append_log(f"HATA: Sistem temizliği başarısız oldu. Yetki hatası olabilir.", is_error=True)
clean_success = False
# 2. Normal Kullanıcı Klasörleri (Tarayıcı önbellekleri, vb.)
if user_paths_to_delete:
self.append_log(f"{len(user_paths_to_delete)} adet kullanıcı dizini temizleniyor...")
for p in user_paths_to_delete:
try:
self.append_log(f" Siliniyor: {p}")
if os.path.islink(p) or os.path.isfile(p):
os.unlink(p)
elif os.path.isdir(p):
shutil.rmtree(p)
except Exception as e:
self.append_log(f"HATA: {p} silinemedi: İzin hatası.", is_error=True)
clean_success = False
self.append_log("Kullanıcı dizini temizliği tamamlandı.")
# Temizlik sonucunu bildir
if clean_success:
QMessageBox.information(self, "Tamamlandı", "Temizlik işlemi başarıyla tamamlandı.")
else:
QMessageBox.warning(self, "Kısmen Tamamlandı", "Temizlik işlemi tamamlandı, ancak bazı dosyalara ulaşılamadığı için silinemedi (izin hatası olabilir).")
# Temizlik sonrası listeyi güncelle
self.taramayi_baslat()
Sistem temizliği (detaylı ve kullanışlı ve tam kontrol sağlayacak şekilde güncellendi), Usb İso yazdırıcı (Artık kendi penceresinde ve detaylı şekilde dd modda usb'nize iso dosyalarınızı daha güvenle yazdırır) , Uygulama pencere boyutu (700 px altına dolayısı ile notebook vb küçük ekranlar içinde uyumlu olacak şekilde, özellikler güncellendi.
Pardus 25 (Debian 13) ve Pardus 23 (Debian 12) tabanlı Linux dağıtımları için geliştirilmiş; sistem izleme, bakım, onarım ve yönetim işlemlerini tek bir modern arayüzde toplayan gelişmiş bir araçtır.
Pardus 25 uyumlu sürümü indirmek için sağ taraftaki "indir" butonuna tıklayın ve çift tıklayıp kurun. Tüm bağımlılıkları 1 kere indirip internetsiz de çalışabilmektedir.
----Özellikler
Uygulama modüler bir yapıya sahiptir ve aşağıdaki temel araçları içerir:
Sistem İzleme & Donanım
Genel Bakış: CPU, RAM, Swap kullanımı, anlık ağ trafiği ve harita üzerinde konum bilgisi. HUD Modu: Masaüstünde yüzen, kompakt sistem bilgi penceresi. Donanım Bilgisi: İşlemci, GPU, Batarya sağlığı, BIOS ve Çekirdek bilgileri. Süreç Yöneticisi: Çalışan işlemleri (PID, CPU, RAM) izleme ve sonlandırma.Ağ & İnternet Ağ Tarayıcı: Wifi ağınızda kaç cihaz bağlı, ip adresleri, isim ve markaları gibi bilgileri görün. Wi-Fi Analizörü: Çevredeki ağları tarama, sinyal gücü grafiği ve kanal önerisi (2.4GHz optimizasyonu). Hız Testi: Çoklu iş parçacığı ile İndirme (Download), Yükleme (Upload) ve Gecikme (Ping) testi. DNS Yönetimi: Tek tıkla Google, Cloudflare, OpenDNS veya Otomatik DNS geçişi. Site Engelleyici: /etc/hosts üzerinden istenmeyen siteleri engelleme. Port Yöneticisi: Açık portları listeleme ve güvenlik duvarı (UFW) üzerinden port açma/kapama.
Bakım & Onarım
Sistem Temizliği: Apt önbelleği, eski kernel logları, tarayıcı çöp dosyaları ve çöp kutusu temizliği. Disk Sağlığı: Disk ömrü analizi ve sağlık raporu. Açılış Analizi: Sistemi yavaşlatan başlangıç servislerinin tespiti. Otomatik Bakım: Paket güncellemeleri, bozuk paket onarımı ve GRUB güncelleme araçları.
Disk & Dosya
Disk Analizcisi: Klasör boyutlarını ağaç yapısında görselleştirme. USB Yazdırıcı: ISO dosyalarını USB belleklere yazdırma (dd arayüzü).
Yönetim & Otomasyon
Cron Yöneticisi: Zamanlanmış görevleri grafik arayüzle ekleme/silme. Özel Komutlar: Sık kullandığınız uzun terminal komutlarını butonlara dönüştürme. Başlangıç Yöneticisi: Sistem açılışında çalışan uygulamaları yönetme.
Kurulum
Bu proje, sistem kütüphanelerindeki farklılıklar nedeniyle Pardus 25 ve Pardus 23 için ayrı paketleme yöntemleri sunar.
Yöntem 1: .deb Paketi ile Kurulum (En Kolay)
GitHub Releases sayfasından sisteminize uygun olan sürümü indirin ve kurun:
Pardus 25 / Debian 13 İçin: sistem-asistani_1.1_amd64.deb
Pardus 23 / Debian 12 İçin: sistem-asistani_1.0_pardus23_amd64.deb
sudo dpkg -i indirilen_paket_adi.deb
sudo apt-get install -f # Eksik bağımlılık varsa tamamlar
Yöntem 2: Paketleme Sihirbazı ile Kurulum (Önerilen)
Bu yöntem, kaynak kodları indirir, gerekli Python kütüphanelerini internetten çeker ve sizin sisteminize özel, internetsiz çalışabilen bir .deb paketi üretir.
Yan taraftan "Kaynak Kod İndir" tıklayın :
ya da Kaynak Kod İndir Zip
Sisteminize Uygun Scripti Çalıştırın:
Pardus 25 (Debian 13) Kullanıyorsanız:
sudo sh ./paketle_pardus25.sh
Pardus 23 (Debian 12) Kullanıyorsanız:
sudo sh ./paketle_pardus23.sh
Oluşan Paketi Kurun: İşlem bittiğinde oluşan .deb paketini çift tıklayarak kurun ya da : (* yerine paketadiniz.deb)
sudo dpkg -i *.deb
Önemli Notlar
Root Yetkisi: Uygulama, sistem dosyalarına müdahale ettiği için (güncelleme, UFW, hosts vb.) kritik işlemlerde pkexec (veya Pardus 23’te policykit) aracılığıyla root şifrenizi isteyecektir.
Uyumluluk:
Pardus 25 / Debian 12 (Bookworm): Tam uyumlu.
Pardus 23 / Debian 11 (Bullseye): Tam uyumlu (Özel paketleme scripti ile).
Meta Veri (Özet)
Linux Sistem, Yönetim, Takip, Bakım, Kontrol aracı