You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

154 lines
6.4 KiB
Python

import os
import shutil
import time
import datetime
import sqlite3
import threading
DB_NAME = 'my_data.db'
class FolderSynchronizer:
def __init__(self, name, folder1, folder2, interval):
self.name = name
self.folder1 = folder1
self.folder2 = folder2
self.interval = interval
self.local = threading.local()
self.create_table()
def get_connection(self):
if not hasattr(self.local, 'conn'):
self.local.conn = sqlite3.connect(DB_NAME)
return self.local.conn
def get_cursor(self):
return self.get_connection().cursor()
def create_table(self):
conn = self.get_connection()
cursor = conn.cursor()
cursor.execute(f'''
CREATE TABLE IF NOT EXISTS {self.name} (
id INTEGER PRIMARY KEY AUTOINCREMENT,
rel_dir TEXT,
file_name TEXT,
modified1 REAL,
exist1 INTEGER,
modified2 REAL,
exist2 INTEGER,
UNIQUE(rel_dir, file_name)
)
''')
conn.commit()
# def delete_job(self):
# conn = self.get_connection()
# cursor = conn.cursor()
# cursor.execute(f"DROP TABLE IF EXISTS {self.name}")
# conn.commit()
# print(f"Job '{self.name}' has been deleted.")
def update_db(self, rel_dir, file_name, modified1, exist1, modified2, exist2):
conn = self.get_connection()
cursor = conn.cursor()
cursor.execute(f'''
INSERT OR REPLACE INTO {self.name}
(rel_dir, file_name, modified1, exist1, modified2, exist2)
VALUES (?, ?, ?, ?, ?, ?)
''', (rel_dir, file_name, modified1, exist1, modified2, exist2))
conn.commit()
def get_file_info(self, rel_dir, file_name):
conn = self.get_connection()
cursor = conn.cursor()
cursor.execute(f'''
SELECT * FROM {self.name}
WHERE rel_dir = ? AND file_name = ?
''', (rel_dir, file_name))
return cursor.fetchone()
def sync_folders(self):
def sync_files(src_folder, dest_folder):
current_time = time.time()
total_sync = 0
count_sync = 0
for root, _, files in os.walk(src_folder):
for filename in files:
try:
src_path = os.path.join(root, filename)
rel_dir = os.path.relpath(root, src_folder)
dest_path = os.path.join(dest_folder, rel_dir, filename)
total_sync += 1
src_modified = os.path.getmtime(src_path)
file_info = self.get_file_info(rel_dir, filename)
if not file_info:
# New file
os.makedirs(os.path.dirname(dest_path), exist_ok=True)
shutil.copy2(src_path, dest_path)
count_sync += 1
dest_modified = current_time
modified1, exist1, modified2, exist2 = src_modified, 1, dest_modified, 1
else:
# Existing file
if src_modified > file_info[3] or not file_info[4]:
shutil.copy2(src_path, dest_path)
count_sync += 1
dest_modified = current_time
modified1, exist1, modified2, exist2 = src_modified, 1, dest_modified, 1
else:
modified1, exist1, modified2, exist2 = src_modified, 1, file_info[5], file_info[6]
except:
pass
finally:
self.update_db(rel_dir, filename, modified1, exist1, modified2, exist2)
return total_sync, count_sync
def check_deleted_files():
conn = self.get_connection()
cursor = conn.cursor()
current_time = time.time()
count_sync = 0
cursor.execute(f"SELECT rel_dir, file_name, modified1, exist1, modified2, exist2 FROM {self.name}")
for row in cursor.fetchall():
rel_dir, file_name, modified1, exist1, modified2, exist2 = row
path1 = os.path.join(self.folder1, rel_dir, file_name)
path2 = os.path.join(self.folder2, rel_dir, file_name)
if not os.path.exists(path1) and not os.path.exists(path2):
count_sync += 1
cursor.execute(f"DELETE FROM {self.name} WHERE rel_dir = ? AND file_name = ?", (rel_dir, file_name))
elif not os.path.exists(path1) and exist1:
modified1 = current_time
if modified1 > modified2:
count_sync += 1
os.remove(path2)
cursor.execute(f"DELETE FROM {self.name} WHERE rel_dir = ? AND file_name = ?", (rel_dir, file_name))
else:
self.update_db(rel_dir, file_name, modified1, 0, modified2, exist2)
elif not os.path.exists(path2) and exist2:
modified2 = current_time
if modified2 > modified1:
count_sync += 1
os.remove(path1)
cursor.execute(f"DELETE FROM {self.name} WHERE rel_dir = ? AND file_name = ?", (rel_dir, file_name))
else:
self.update_db(rel_dir, file_name, modified1, exist1, modified2, 0)
conn.commit()
return count_sync
total_sync1, count_sync1 = sync_files(self.folder1, self.folder2)
total_sync2, count_sync2 = sync_files(self.folder2, self.folder1)
count_sync3 = check_deleted_files()
total_sync = max(total_sync1, total_sync2)
count_sync = count_sync1 + count_sync2 + count_sync3
# now = datetime.datetime.now()
# formatted_datetime = now.strftime("[%Y-%m-%d %H:%M:%S]")
# return f"[{self.name}] \'{self.folder1} <-> {self.folder2}\' Sync completed! (sync count: {count_sync}, total files: {total_sync})"
return f"[{self.name}] Sync completed! (sync count: {count_sync}, total files: {total_sync})"