Skip to content

Commit ed7280c

Browse files
authored
Create FileSyncPRO.py
1 parent ed0aceb commit ed7280c

1 file changed

Lines changed: 326 additions & 0 deletions

File tree

Lines changed: 326 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,326 @@
1+
# ==========================================================
2+
# FileSync PRO - File Synchronization Tool
3+
# Professional Desktop Tool
4+
# ==========================================================
5+
6+
import os
7+
import sys
8+
import shutil
9+
import threading
10+
import time
11+
import traceback
12+
from datetime import datetime
13+
from queue import Queue, Empty
14+
15+
import tkinter as tk
16+
from tkinter import filedialog, messagebox
17+
18+
import ttkbootstrap as tb
19+
from ttkbootstrap.constants import *
20+
21+
22+
# =================== APP CONFIG ===================
23+
24+
APP_NAME = "FileSync PRO"
25+
APP_VERSION = "1.0.0"
26+
27+
28+
# =================== APP ===================
29+
30+
app = tk.Tk()
31+
app.title(f"{APP_NAME} {APP_VERSION}")
32+
app.geometry("1100x620")
33+
34+
tb.Style("darkly")
35+
36+
37+
# =================== FLAGS ===================
38+
39+
ui_queue = Queue()
40+
41+
source_folder = tb.StringVar()
42+
target_folder = tb.StringVar()
43+
44+
sync_running = False
45+
auto_sync = False
46+
47+
48+
# =================== UTIL ===================
49+
50+
def resource_path(file_name):
51+
base_path = getattr(sys, "_MEIPASS", os.path.dirname(os.path.abspath(__file__)))
52+
return os.path.join(base_path, file_name)
53+
54+
def log_error():
55+
with open("error.log","a",encoding="utf-8") as f:
56+
f.write(traceback.format_exc()+"\n")
57+
58+
59+
def log(msg):
60+
ui_queue.put(("log",msg))
61+
62+
63+
def resource_path(file_name):
64+
base = getattr(sys,"_MEIPASS",os.path.dirname(os.path.abspath(__file__)))
65+
return os.path.join(base,file_name)
66+
67+
68+
# =================== FILE SYNC ENGINE ===================
69+
70+
def sync_folders():
71+
72+
global sync_running
73+
74+
if not source_folder.get() or not target_folder.get():
75+
messagebox.showerror("Error","Select source and target folders")
76+
return
77+
78+
sync_running = True
79+
80+
src = source_folder.get()
81+
dst = target_folder.get()
82+
83+
log("🔄 Synchronization started")
84+
85+
try:
86+
87+
for root, dirs, files in os.walk(src):
88+
89+
if not sync_running:
90+
break
91+
92+
rel_path = os.path.relpath(root, src)
93+
dst_path = os.path.join(dst, rel_path)
94+
95+
if not os.path.exists(dst_path):
96+
os.makedirs(dst_path)
97+
98+
for file in files:
99+
100+
src_file = os.path.join(root,file)
101+
dst_file = os.path.join(dst_path,file)
102+
103+
try:
104+
105+
if not os.path.exists(dst_file) or \
106+
os.path.getmtime(src_file) > os.path.getmtime(dst_file):
107+
108+
shutil.copy2(src_file,dst_file)
109+
110+
log(f"✔ Synced: {file}")
111+
112+
except:
113+
log_error()
114+
115+
log("✅ Synchronization finished")
116+
117+
except:
118+
log_error()
119+
120+
sync_running = False
121+
122+
123+
# =================== AUTO SYNC ===================
124+
125+
def auto_sync_loop():
126+
127+
global auto_sync
128+
129+
auto_sync = True
130+
131+
log("⏱ Auto Sync started")
132+
133+
while auto_sync:
134+
135+
sync_folders()
136+
137+
for i in range(30):
138+
139+
if not auto_sync:
140+
break
141+
142+
time.sleep(1)
143+
144+
log("🛑 Auto Sync stopped")
145+
146+
147+
def stop_auto_sync():
148+
global auto_sync
149+
auto_sync = False
150+
151+
152+
# =================== BROWSE ===================
153+
154+
def browse_source():
155+
156+
folder = filedialog.askdirectory()
157+
158+
if folder:
159+
source_folder.set(folder)
160+
161+
162+
def browse_target():
163+
164+
folder = filedialog.askdirectory()
165+
166+
if folder:
167+
target_folder.set(folder)
168+
169+
170+
# =================== ABOUT ===================
171+
172+
def show_about():
173+
174+
messagebox.showinfo(
175+
f"About {APP_NAME}",
176+
f"{APP_NAME} v{APP_VERSION}\n\n"
177+
"Professional File Synchronization Tool\n\n"
178+
"Features:\n"
179+
"• 🔄 One-click folder synchronization\n"
180+
"• 📁 Source → Destination mirror\n"
181+
"• ⚡ Fast incremental sync\n"
182+
"• ⏱ Automatic background syncing\n"
183+
"• 🧠 Smart file modification detection\n"
184+
"• 📜 Real-time activity log\n"
185+
"• 🖥 Modern UI with ttkbootstrap\n\n"
186+
"Built with:\n"
187+
"Python • Tkinter • ttkbootstrap\n\n"
188+
"Designed for developers, IT admins,\n"
189+
"and productivity workflows.\n\n"
190+
"© 2026 Mate Technologies\n"
191+
"https://matetools.gumroad.com"
192+
)
193+
194+
195+
# =================== MENU ===================
196+
197+
menubar = tb.Menu(app)
198+
199+
help_menu = tb.Menu(menubar,tearoff=0)
200+
help_menu.add_command(label="About",command=show_about)
201+
202+
menubar.add_cascade(label="Help",menu=help_menu)
203+
204+
app.config(menu=menubar)
205+
206+
207+
try:
208+
app.iconbitmap(resource_path("logo.ico"))
209+
except:
210+
pass
211+
212+
213+
# =================== TITLE ===================
214+
215+
title_frame = tb.Frame(app)
216+
title_frame.pack(pady=(10,10))
217+
218+
tb.Label(
219+
title_frame,
220+
text=APP_NAME,
221+
font=("Segoe UI",26,"bold"),
222+
bootstyle="primary"
223+
).pack()
224+
225+
tb.Label(
226+
title_frame,
227+
text=f"v{APP_VERSION} • Professional File Synchronization Tool",
228+
font=("Segoe UI",10,"italic"),
229+
foreground="#9ca3af"
230+
).pack()
231+
232+
tb.Label(
233+
title_frame,
234+
text="Synchronize folders, backup files, and mirror directories easily",
235+
font=("Segoe UI",9),
236+
foreground="#6b7280"
237+
).pack()
238+
239+
240+
# =================== CONTROLS ===================
241+
242+
frame_controls = tb.Labelframe(app,text="Controls",padding=10)
243+
frame_controls.pack(fill="x",padx=10,pady=6)
244+
245+
tb.Button(
246+
frame_controls,
247+
text="🔄 Start Sync",
248+
bootstyle="success",
249+
command=lambda: threading.Thread(target=sync_folders,daemon=True).start()
250+
).pack(side="left",padx=5)
251+
252+
tb.Button(
253+
frame_controls,
254+
text="⏱ Start Auto Sync",
255+
bootstyle="warning",
256+
command=lambda: threading.Thread(target=auto_sync_loop,daemon=True).start()
257+
).pack(side="left",padx=5)
258+
259+
tb.Button(
260+
frame_controls,
261+
text="🛑 Stop Auto Sync",
262+
bootstyle="danger",
263+
command=stop_auto_sync
264+
).pack(side="left",padx=5)
265+
266+
267+
# =================== SETTINGS ===================
268+
269+
frame_settings = tb.Labelframe(app,text="Folders",padding=10)
270+
frame_settings.pack(fill="x",padx=10,pady=6)
271+
272+
tb.Label(frame_settings,text="Source Folder").pack(side="left")
273+
274+
tb.Entry(frame_settings,textvariable=source_folder,width=40).pack(side="left",padx=5)
275+
276+
tb.Button(frame_settings,text="Browse",command=browse_source).pack(side="left",padx=5)
277+
278+
tb.Label(frame_settings,text="Target Folder").pack(side="left",padx=10)
279+
280+
tb.Entry(frame_settings,textvariable=target_folder,width=40).pack(side="left",padx=5)
281+
282+
tb.Button(frame_settings,text="Browse",command=browse_target).pack(side="left",padx=5)
283+
284+
285+
# =================== LOG PANEL ===================
286+
287+
log_frame = tb.Labelframe(app,text="Activity Log",padding=10)
288+
log_frame.pack(fill="both",expand=True,padx=10,pady=6)
289+
290+
log_text = tk.Text(log_frame)
291+
log_text.pack(side="left",fill="both",expand=True)
292+
293+
scroll = tk.Scrollbar(log_frame,command=log_text.yview)
294+
scroll.pack(side="right",fill="y")
295+
296+
log_text.config(yscrollcommand=scroll.set,state="disabled")
297+
298+
299+
# =================== UI QUEUE ===================
300+
301+
def process_ui_queue():
302+
303+
try:
304+
305+
while True:
306+
307+
cmd,data = ui_queue.get_nowait()
308+
309+
if cmd=="log":
310+
311+
log_text.config(state="normal")
312+
log_text.insert("end",data+"\n")
313+
log_text.see("end")
314+
log_text.config(state="disabled")
315+
316+
except Empty:
317+
pass
318+
319+
app.after(100,process_ui_queue)
320+
321+
322+
# =================== START ===================
323+
324+
app.after(100,process_ui_queue)
325+
326+
app.mainloop()

0 commit comments

Comments
 (0)