Applied settings; app now functions in a basic way
This commit is contained in:
parent
3d97c3b698
commit
ca2c8f2ade
5 changed files with 134 additions and 25 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -1,4 +1,5 @@
|
|||
.vscode/
|
||||
__pycache__/
|
||||
venv/
|
||||
plan.svg
|
||||
plan.svg
|
||||
data/file_rules_custom.json
|
||||
|
|
|
|||
66
app.py
66
app.py
|
|
@ -19,12 +19,15 @@ def set_debug_mode(value):
|
|||
debug_mode = value
|
||||
|
||||
class App(tk.Tk):
|
||||
def __init__(self, width=600, height=400):
|
||||
def __init__(self, width=640, height=480):
|
||||
super().__init__()
|
||||
self.title("Download Utils")
|
||||
self.current_mode = "all"
|
||||
self.option_add('*tearOff', tk.FALSE)
|
||||
self.fm = fm.Manager(True)
|
||||
self.log = list()
|
||||
self.gui()
|
||||
self.prep()
|
||||
|
||||
screen_width = self.winfo_screenwidth()
|
||||
screen_height = self.winfo_screenheight()
|
||||
|
|
@ -46,6 +49,28 @@ class App(tk.Tk):
|
|||
str(ut.format_bytes(v["size"])))
|
||||
self.fileview.insert("", tk.END, k, values=values)
|
||||
|
||||
def load_config(self, filepath="data/file_rules_custom.json"):
|
||||
data = ut.load_json_file(filepath)
|
||||
self.fm.setup_file_rules(data, True)
|
||||
|
||||
def save_config(self, filepath="data/file_rules_custom.json"):
|
||||
ut.save_json_file(filepath, self.fm.filemodes)
|
||||
|
||||
def update_mode_data(self, mode, key, value):
|
||||
print(f"{key} : {value}")
|
||||
if not mode in self.fm.filemodes: return
|
||||
self.fm.filemodes[mode].update({key: value})
|
||||
|
||||
def set_rules_variables(self, key):
|
||||
if not key in self.fm.filemodes: return
|
||||
data = self.fm.filemodes[key]
|
||||
self.v_radio.set(data["action"])
|
||||
self.v_targetdir.set(data["destination"])
|
||||
if type(data["extensions"]) == list: # Needs improvement
|
||||
self.v_extstr.set(", ".join(data["extensions"]))
|
||||
else:
|
||||
self.v_extstr.set(data["extensions"])
|
||||
|
||||
def select_mode_from_list(self, event):
|
||||
key = ""
|
||||
value = self.w_list.get(self.w_list.curselection())
|
||||
|
|
@ -54,13 +79,21 @@ class App(tk.Tk):
|
|||
key = k
|
||||
break
|
||||
|
||||
if len(key) == 0: return # Do error
|
||||
if len(key) > 0:
|
||||
self.current_mode = key
|
||||
self.set_rules_variables(key)
|
||||
|
||||
data = self.fm.filemodes[key]
|
||||
print(data)
|
||||
self.v_radio.set(data["action"])
|
||||
self.v_targetdir.set(data["destination"])
|
||||
self.v_extstr.set(", ".join(data["extensions"]))
|
||||
def prep(self):
|
||||
self.update_fileview()
|
||||
if self.current_mode in self.fm.filemodes:
|
||||
self.set_rules_variables(self.current_mode)
|
||||
|
||||
def run_task(self):
|
||||
print("Task started")
|
||||
self.fm.run_task()
|
||||
|
||||
def run_backup(self):
|
||||
print("Backup started")
|
||||
|
||||
def gui(self):
|
||||
self.gui_menu()
|
||||
|
|
@ -76,7 +109,6 @@ class App(tk.Tk):
|
|||
self.config(menu=a_menu)
|
||||
|
||||
a_menu_file = tk.Menu(a_menu)
|
||||
a_menu_file.add_command(label="Open")
|
||||
a_menu_file.add_command(label="Exit", command=self.destroy)
|
||||
|
||||
a_menu.add_cascade(
|
||||
|
|
@ -90,13 +122,13 @@ class App(tk.Tk):
|
|||
|
||||
box = ttk.Frame(frame)
|
||||
|
||||
button = ttk.Button(box, text="Start Task")
|
||||
button = ttk.Button(box, text="Start Task", command=self.run_task)
|
||||
button.grid(column=0, row=0, pady=5)
|
||||
|
||||
button = ttk.Button(box, text="Refresh", command=self.update_fileview)
|
||||
button.grid(column=1, row=0, pady=5)
|
||||
|
||||
button = ttk.Button(box, text="Backup")
|
||||
button = ttk.Button(box, text="Backup", command=self.run_backup)
|
||||
button.grid(column=2, row=0, pady=5)
|
||||
|
||||
box.pack(side=tk.TOP, fill=tk.X)
|
||||
|
|
@ -113,19 +145,18 @@ class App(tk.Tk):
|
|||
command=self.fileview.yview)
|
||||
self.fileview.configure(yscrollcommand=sbar.set)
|
||||
|
||||
self.update_fileview()
|
||||
|
||||
self.fileview.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
|
||||
sbar.pack(side=tk.RIGHT, fill=tk.Y)
|
||||
|
||||
return frame
|
||||
|
||||
def gui_rules(self):
|
||||
um = self.update_mode_data
|
||||
frame = ttk.Frame(self.book)
|
||||
|
||||
box = ttk.Frame(frame)
|
||||
|
||||
button = ttk.Button(box, text="Save Config")
|
||||
button = ttk.Button(box, text="Save Config", command=self.save_config)
|
||||
button.grid(column=0, row=0, pady=5)
|
||||
|
||||
button = ttk.Button(box, text="Reset")
|
||||
|
|
@ -142,7 +173,7 @@ class App(tk.Tk):
|
|||
self.w_list = tk.Listbox(main, listvariable=self.v_modelist,
|
||||
selectmode=tk.SINGLE)
|
||||
self.w_list.bind('<<ListboxSelect>>', self.select_mode_from_list)
|
||||
self.w_list.grid(row=0, column=0, sticky=tk.NS)
|
||||
self.w_list.grid(row=0, column=0, padx=5, sticky=tk.NSEW)
|
||||
|
||||
details = ttk.Frame(main)
|
||||
|
||||
|
|
@ -150,10 +181,11 @@ class App(tk.Tk):
|
|||
|
||||
self.v_radio = tk.StringVar()
|
||||
self.v_actions = ("move", "copy", "delete", "ignore")
|
||||
f_radio = lambda: um(self.current_mode, "action", self.v_radio.get())
|
||||
for s in self.v_actions:
|
||||
str = f"{s.capitalize()} "
|
||||
radio = ttk.Radiobutton(i_frame, text=str, value=s,
|
||||
variable=self.v_radio)
|
||||
variable=self.v_radio, command = f_radio)
|
||||
radio.pack(side=tk.LEFT)
|
||||
i_frame.pack(side=tk.TOP, anchor=tk.W)
|
||||
|
||||
|
|
@ -165,7 +197,9 @@ class App(tk.Tk):
|
|||
label.pack(side=tk.TOP, anchor=tk.W)
|
||||
|
||||
self.v_targetdir = tk.StringVar()
|
||||
f_targetdir = lambda e: um(self.current_mode, "destination", self.v_targetdir.get())
|
||||
entry = ttk.Entry(i_frame, textvariable=self.v_targetdir)
|
||||
entry.bind('<Return>', f_targetdir)
|
||||
entry.pack(side=tk.TOP, fill=tk.X)
|
||||
|
||||
i_frame.pack(side=tk.TOP, fill=tk.X)
|
||||
|
|
@ -177,7 +211,9 @@ class App(tk.Tk):
|
|||
label.pack(side=tk.TOP, anchor=tk.W)
|
||||
|
||||
self.v_extstr = tk.StringVar()
|
||||
f_extstr = lambda e: um(self.current_mode, "extensions", self.v_extstr.get())
|
||||
entry = ttk.Entry(i_frame, textvariable=self.v_extstr)
|
||||
entry.bind('<Return>', f_extstr)
|
||||
entry.pack(side=tk.TOP, fill=tk.X)
|
||||
|
||||
i_frame.pack(side=tk.TOP, fill=tk.X)
|
||||
|
|
|
|||
|
|
@ -3,7 +3,10 @@
|
|||
__author__ = "Gull"
|
||||
|
||||
import os
|
||||
import json
|
||||
import shutil
|
||||
import utils as ut
|
||||
|
||||
debug_mode = True
|
||||
|
||||
class Manager:
|
||||
def __init__(self, auto_config=False):
|
||||
|
|
@ -11,10 +14,11 @@ class Manager:
|
|||
self.filedata = dict()
|
||||
self.filemodes = dict() # Contains file mode data
|
||||
self.filetypes = dict() # Maps file extensions to modes
|
||||
self.config_path = "data/file_rules_default.json"
|
||||
|
||||
if auto_config:
|
||||
self.set_directory(self.get_directory())
|
||||
self.setup_file_rules()
|
||||
self.setup_file_rules(ut.load_json_file(self.config_path))
|
||||
|
||||
def get_directory(self, target="Downloads"):
|
||||
dir = os.path.join(os.path.expanduser("~"), target)
|
||||
|
|
@ -25,12 +29,20 @@ class Manager:
|
|||
if os.path.exists(dir):
|
||||
self.dir = dir
|
||||
|
||||
def setup_file_rules(self, file="data/settings_default.json", data=None):
|
||||
with open(file) as f:
|
||||
data = json.load(f)
|
||||
self.filemodes = data["filemodes"]
|
||||
self.filetypes.clear()
|
||||
for k, v in self.filemodes.items():
|
||||
def setup_file_rules(self, data, reset=False):
|
||||
if reset: self.filemodes.clear()
|
||||
if not "filemodes" in data: return
|
||||
|
||||
filemodes = data["filemodes"]
|
||||
for k, v in filemodes.items():
|
||||
self.filemodes[k] = v
|
||||
|
||||
self.match_file_types()
|
||||
|
||||
def match_file_types(self):
|
||||
self.filetypes.clear()
|
||||
for k, v in self.filemodes.items():
|
||||
if "extensions" in v:
|
||||
for ext in v["extensions"]:
|
||||
self.filetypes[ext] = k
|
||||
|
||||
|
|
@ -46,3 +58,51 @@ class Manager:
|
|||
st = entry.stat()
|
||||
data = {"time": st.st_mtime, "size": st.st_size}
|
||||
self.filedata[entry.name] = data
|
||||
|
||||
def run_task(self):
|
||||
self.match_file_types() # Updates file types dict
|
||||
for k, v in self.filedata.items():
|
||||
fullpath = os.path.join(self.dir, k)
|
||||
if os.path.exists(fullpath):
|
||||
_, ext = os.path.splitext(fullpath)
|
||||
ext = ext[1:].lower()
|
||||
mode = self.filetypes[ext] if ext in self.filetypes else "other"
|
||||
v["mode"] = mode
|
||||
v["fullpath"] = fullpath
|
||||
|
||||
for k, v in self.filedata.items():
|
||||
rule = self.filemodes[v["mode"]]
|
||||
if rule["action"] == "move":
|
||||
move(v["fullpath"], rule["destination"])
|
||||
elif rule["action"] == "copy":
|
||||
copy(v["fullpath"], rule["destination"])
|
||||
elif rule["action"] == "delete":
|
||||
delete(v["fullpath"])
|
||||
|
||||
def parse_dir(dir):
|
||||
"""Checks if a directory exists, and if it is for the user."""
|
||||
if dir[0] == "~":
|
||||
dir = dir.lstrip("~/")
|
||||
dir = os.path.join(os.path.expanduser("~"), dir)
|
||||
return dir
|
||||
|
||||
def move(src, dst):
|
||||
src, dst = parse_dir(src), parse_dir(dst)
|
||||
if debug_mode:
|
||||
print(f"Move: {src} > {dst}")
|
||||
else:
|
||||
shutil.move(src, dst)
|
||||
|
||||
def copy(src, dst):
|
||||
src, dst = parse_dir(src), parse_dir(dst)
|
||||
if debug_mode:
|
||||
print(f"Copy: {src} > {dst}")
|
||||
else:
|
||||
shutil.copy2(src, dst)
|
||||
|
||||
def delete(src):
|
||||
src = parse_dir(src)
|
||||
if debug_mode:
|
||||
print(f"Delete: {src}")
|
||||
else:
|
||||
os.remove(src)
|
||||
14
utils.py
14
utils.py
|
|
@ -3,6 +3,7 @@
|
|||
__author__ = "Gull"
|
||||
|
||||
import time
|
||||
import json
|
||||
|
||||
KILOBYTES = 1024
|
||||
|
||||
|
|
@ -29,4 +30,15 @@ def format_bytes(bytes):
|
|||
|
||||
def format_date(timestamp):
|
||||
"""Returns a time string (ISO 8601) from the given integer timestamp."""
|
||||
return time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(timestamp))
|
||||
return time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(timestamp))
|
||||
|
||||
def load_json_file(filepath):
|
||||
"""Opens a JSON file, and returns JSON data as a dict."""
|
||||
with open(filepath, "r", encoding="utf-8") as f:
|
||||
data = json.load(f)
|
||||
return data
|
||||
|
||||
def save_json_file(filepath, data, raw=False):
|
||||
"""Saves a JSON file, given a dict."""
|
||||
with open(filepath, "w", encoding="utf-8") as f:
|
||||
json.dump(data, f, sort_keys=True, indent=None if raw else 2)
|
||||
Loading…
Add table
Add a link
Reference in a new issue