Ultima attività 1760165031

desktop_organizer.py Raw
1import os
2import shutil
3import tkinter as tk
4from tkinter import ttk, messagebox, scrolledtext
5from pathlib import Path
6import threading
7from datetime import datetime
8
9class DesktopOrganizerGUI:
10 def __init__(self, root):
11 self.root = root
12 self.root.title("Desktop Organizer - Windows 11")
13 self.root.geometry("700x600")
14 self.root.resizable(False, False)
15
16 # Стилизация
17 style = ttk.Style()
18 style.theme_use('clam')
19
20 # Определяне на Desktop пътя
21 self.desktop_path = Path.home() / "Desktop"
22
23 # Категории за файлове
24 self.categories = {
25 "Документи": [".pdf", ".doc", ".docx", ".txt", ".rtf", ".odt", ".xls", ".xlsx", ".ppt", ".pptx"],
26 "Изображения": [".jpg", ".jpeg", ".png", ".gif", ".bmp", ".svg", ".ico", ".webp", ".tiff"],
27 "Видео": [".mp4", ".avi", ".mkv", ".mov", ".wmv", ".flv", ".webm"],
28 "Музика": [".mp3", ".wav", ".flac", ".aac", ".ogg", ".wma", ".m4a"],
29 "Архиви": [".zip", ".rar", ".7z", ".tar", ".gz", ".bz2"],
30 "Програми": [".exe", ".msi", ".bat", ".cmd"],
31 "Код": [".py", ".js", ".html", ".css", ".cpp", ".java", ".c", ".h", ".json", ".xml"],
32 "Други": []
33 }
34
35 # Системни файлове и папки за игнориране
36 self.system_items = ["desktop.ini", "Thumbs.db", "$RECYCLE.BIN"]
37
38 self.create_widgets()
39
40 def create_widgets(self):
41 # Заглавие
42 title_frame = tk.Frame(self.root, bg="#0078D4", height=80)
43 title_frame.pack(fill="x")
44 title_frame.pack_propagate(False)
45
46 title_label = tk.Label(
47 title_frame,
48 text="🧹 Desktop Organizer",
49 font=("Segoe UI", 20, "bold"),
50 bg="#0078D4",
51 fg="white"
52 )
53 title_label.pack(pady=20)
54
55 # Основна рамка
56 main_frame = tk.Frame(self.root, padx=20, pady=20)
57 main_frame.pack(fill="both", expand=True)
58
59 # Информация
60 info_label = tk.Label(
61 main_frame,
62 text=f"📂 Desktop път: {self.desktop_path}",
63 font=("Segoe UI", 10),
64 justify="left",
65 anchor="w"
66 )
67 info_label.pack(fill="x", pady=(0, 10))
68
69 # Настройки рамка
70 settings_frame = tk.LabelFrame(
71 main_frame,
72 text="⚙️ Настройки",
73 font=("Segoe UI", 11, "bold"),
74 padx=15,
75 pady=15
76 )
77 settings_frame.pack(fill="x", pady=(0, 15))
78
79 self.keep_shortcuts = tk.BooleanVar(value=True)
80 tk.Checkbutton(
81 settings_frame,
82 text="✓ Запази всички пряки пътища (.lnk)",
83 variable=self.keep_shortcuts,
84 font=("Segoe UI", 10)
85 ).pack(anchor="w", pady=5)
86
87 self.keep_folders = tk.BooleanVar(value=True)
88 tk.Checkbutton(
89 settings_frame,
90 text="✓ Запази съществуващите папки на мястото им",
91 variable=self.keep_folders,
92 font=("Segoe UI", 10)
93 ).pack(anchor="w", pady=5)
94
95 self.main_folder_name = tk.StringVar(value="Организиран Desktop")
96 folder_frame = tk.Frame(settings_frame)
97 folder_frame.pack(fill="x", pady=5)
98 tk.Label(
99 folder_frame,
100 text="📁 Име на главната папка:",
101 font=("Segoe UI", 10)
102 ).pack(side="left")
103 tk.Entry(
104 folder_frame,
105 textvariable=self.main_folder_name,
106 font=("Segoe UI", 10),
107 width=30
108 ).pack(side="left", padx=10)
109
110 # Бутони
111 button_frame = tk.Frame(main_frame)
112 button_frame.pack(fill="x", pady=(0, 15))
113
114 self.preview_btn = tk.Button(
115 button_frame,
116 text="👁️ Преглед",
117 font=("Segoe UI", 11, "bold"),
118 bg="#0078D4",
119 fg="white",
120 padx=20,
121 pady=10,
122 cursor="hand2",
123 command=self.preview_organization
124 )
125 self.preview_btn.pack(side="left", padx=(0, 10))
126
127 self.organize_btn = tk.Button(
128 button_frame,
129 text="🚀 Организирай Desktop",
130 font=("Segoe UI", 11, "bold"),
131 bg="#107C10",
132 fg="white",
133 padx=20,
134 pady=10,
135 cursor="hand2",
136 command=self.start_organization
137 )
138 self.organize_btn.pack(side="left")
139
140 # Лог рамка
141 log_frame = tk.LabelFrame(
142 main_frame,
143 text="📋 Дневник на действията",
144 font=("Segoe UI", 11, "bold"),
145 padx=10,
146 pady=10
147 )
148 log_frame.pack(fill="both", expand=True)
149
150 self.log_text = scrolledtext.ScrolledText(
151 log_frame,
152 font=("Consolas", 9),
153 wrap=tk.WORD,
154 height=15,
155 state="disabled"
156 )
157 self.log_text.pack(fill="both", expand=True)
158
159 # Progress bar
160 self.progress = ttk.Progressbar(
161 main_frame,
162 mode="indeterminate"
163 )
164 self.progress.pack(fill="x", pady=(10, 0))
165
166 def log(self, message):
167 self.log_text.config(state="normal")
168 timestamp = datetime.now().strftime("%H:%M:%S")
169 self.log_text.insert(tk.END, f"[{timestamp}] {message}\n")
170 self.log_text.see(tk.END)
171 self.log_text.config(state="disabled")
172 self.root.update()
173
174 def get_category(self, file_path):
175 ext = file_path.suffix.lower()
176 for category, extensions in self.categories.items():
177 if ext in extensions:
178 return category
179 return "Други"
180
181 def should_ignore(self, item_path):
182 # Игнорира системни файлове
183 if item_path.name in self.system_items:
184 return True
185 # Игнорира скрити файлове
186 if item_path.name.startswith('.'):
187 return True
188 return False
189
190 def analyze_desktop(self):
191 items_to_move = {}
192 items_to_keep = []
193
194 for item in self.desktop_path.iterdir():
195 if self.should_ignore(item):
196 continue
197
198 # Запазва пряки пътища
199 if self.keep_shortcuts.get() and item.suffix.lower() == ".lnk":
200 items_to_keep.append(item.name)
201 continue
202
203 # Запазва папки
204 if item.is_dir():
205 if self.keep_folders.get():
206 items_to_keep.append(item.name)
207 continue
208 else:
209 # Папките ще бъдат преместени в главната папка
210 if "Папки" not in items_to_move:
211 items_to_move["Папки"] = []
212 items_to_move["Папки"].append(item)
213 continue
214
215 # Категоризира файлове
216 if item.is_file():
217 category = self.get_category(item)
218 if category not in items_to_move:
219 items_to_move[category] = []
220 items_to_move[category].append(item)
221
222 return items_to_move, items_to_keep
223
224 def preview_organization(self):
225 self.log("🔍 Анализиране на Desktop...")
226 items_to_move, items_to_keep = self.analyze_desktop()
227
228 self.log("\n✅ Файлове/папки, които ще ОСТАНАТ на Desktop:")
229 if items_to_keep:
230 for item in items_to_keep:
231 self.log(f"{item}")
232 else:
233 self.log(" (няма)")
234
235 self.log("\n📦 Файлове, които ще бъдат ОРГАНИЗИРАНИ:")
236 total_files = 0
237 for category, files in items_to_move.items():
238 if files:
239 self.log(f" 📁 {category}: {len(files)} файла")
240 total_files += len(files)
241
242 self.log(f"\n📊 Общо файлове за организиране: {total_files}")
243 self.log("=" * 60)
244
245 def organize_desktop(self):
246 try:
247 self.log("🚀 Започване на организация...")
248 items_to_move, items_to_keep = self.analyze_desktop()
249
250 if not items_to_move:
251 self.log("✓ Desktop-ът вече е организиран!")
252 messagebox.showinfo("Готово", "Няма файлове за организиране!")
253 return
254
255 # Създаване на главна папка
256 main_folder = self.desktop_path / self.main_folder_name.get()
257 main_folder.mkdir(exist_ok=True)
258 self.log(f"✓ Създадена главна папка: {main_folder.name}")
259
260 # Преместване на файлове по категории
261 moved_count = 0
262 for category, files in items_to_move.items():
263 if not files:
264 continue
265
266 category_folder = main_folder / category
267 category_folder.mkdir(exist_ok=True)
268 self.log(f"\n📁 Обработка на категория: {category}")
269
270 for file_path in files:
271 try:
272 dest = category_folder / file_path.name
273
274 # Ако файлът съществува, добави номер
275 if dest.exists():
276 base = dest.stem
277 ext = dest.suffix
278 counter = 1
279 while dest.exists():
280 dest = category_folder / f"{base}_{counter}{ext}"
281 counter += 1
282
283 shutil.move(str(file_path), str(dest))
284 self.log(f" ✓ Преместен: {file_path.name}")
285 moved_count += 1
286 except Exception as e:
287 self.log(f" ✗ Грешка при преместване на {file_path.name}: {str(e)}")
288
289 self.log(f"\n🎉 Организацията завърши успешно!")
290 self.log(f"📊 Преместени файлове: {moved_count}")
291 self.log(f"✓ Запазени на Desktop: {len(items_to_keep)} елемента")
292
293 messagebox.showinfo(
294 "Успех!",
295 f"Desktop-ът е организиран успешно!\n\n"
296 f"Преместени: {moved_count} файла\n"
297 f"Запазени: {len(items_to_keep)} елемента"
298 )
299
300 except Exception as e:
301 self.log(f"❌ ГРЕШКА: {str(e)}")
302 messagebox.showerror("Грешка", f"Възникна грешка:\n{str(e)}")
303 finally:
304 self.progress.stop()
305 self.organize_btn.config(state="normal")
306 self.preview_btn.config(state="normal")
307
308 def start_organization(self):
309 result = messagebox.askyesno(
310 "Потвърждение",
311 "Сигурни ли сте, че искате да организирате Desktop-а?\n\n"
312 "Препоръчваме първо да използвате 'Преглед'."
313 )
314
315 if result:
316 self.organize_btn.config(state="disabled")
317 self.preview_btn.config(state="disabled")
318 self.progress.start()
319 self.log_text.config(state="normal")
320 self.log_text.delete(1.0, tk.END)
321 self.log_text.config(state="disabled")
322
323 # Стартиране в отделна нишка
324 thread = threading.Thread(target=self.organize_desktop)
325 thread.daemon = True
326 thread.start()
327
328if __name__ == "__main__":
329 root = tk.Tk()
330 app = DesktopOrganizerGUI(root)
331 root.mainloop()