Added logging, cleaned up some functions
This commit is contained in:
parent
ca2c8f2ade
commit
5a04dd37f1
5 changed files with 85 additions and 43 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -1,5 +1,7 @@
|
|||
.vscode/
|
||||
__pycache__/
|
||||
venv/
|
||||
venv_linux/
|
||||
plan.svg
|
||||
data/file_rules_custom.json
|
||||
app.log
|
||||
|
|
|
|||
44
app.py
44
app.py
|
|
@ -5,6 +5,7 @@ __author__ = "Gull"
|
|||
|
||||
import tkinter as tk
|
||||
import file_manager as fm
|
||||
import logging as log
|
||||
import utils as ut
|
||||
from tkinter import ttk
|
||||
from tkinter.messagebox import showinfo
|
||||
|
|
@ -18,10 +19,22 @@ def set_debug_mode(value):
|
|||
else:
|
||||
debug_mode = value
|
||||
|
||||
def setup_log():
|
||||
import sys
|
||||
log.basicConfig(
|
||||
filename="app.log",
|
||||
filemode="w",
|
||||
level=log.DEBUG,
|
||||
format="{asctime}: [{levelname}] {message}",
|
||||
style="{")
|
||||
|
||||
log.getLogger().addHandler(log.StreamHandler(sys.stdout)) # Console
|
||||
log.info("App started")
|
||||
|
||||
class App(tk.Tk):
|
||||
def __init__(self, width=640, height=480):
|
||||
super().__init__()
|
||||
self.title("Download Utils")
|
||||
self.title("Download Sorter")
|
||||
self.current_mode = "all"
|
||||
self.option_add('*tearOff', tk.FALSE)
|
||||
self.fm = fm.Manager(True)
|
||||
|
|
@ -37,9 +50,10 @@ class App(tk.Tk):
|
|||
|
||||
self.geometry(f"{width}x{height}+{center_x}+{center_y}")
|
||||
|
||||
def update_fileview(self):
|
||||
def update_fileview(self, tree=True):
|
||||
self.fm.set_directory(self.fm.get_directory())
|
||||
self.fm.update_file_data()
|
||||
log.info(f"Processed file view with {len(self.fm.filedata)} items")
|
||||
|
||||
while len(self.fileview.get_children()) > 0:
|
||||
self.fileview.delete(self.fileview.get_children()[-1])
|
||||
|
|
@ -49,17 +63,25 @@ 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)
|
||||
def load_config(self, filepath="%/Temp/file_rules_custom.json"):
|
||||
data = ut.load_json_file(ut.parse_dir(filepath))
|
||||
self.fm.setup_file_rules(data, True)
|
||||
log.info(f"Loaded custom file rules")
|
||||
|
||||
def save_config(self, filepath="data/file_rules_custom.json"):
|
||||
ut.save_json_file(filepath, self.fm.filemodes)
|
||||
def save_config(self, filepath="%/Temp/file_rules_custom.json"):
|
||||
ut.save_json_file(ut.parse_dir(filepath), self.fm.filemodes)
|
||||
log.info(f"Saved custom file rules")
|
||||
|
||||
def reset_config(self):
|
||||
data = ut.load_json_file(self.fm.config_path)
|
||||
self.fm.setup_file_rules(data, True)
|
||||
self.prep()
|
||||
log.info(f"Reloaded default file rules")
|
||||
|
||||
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})
|
||||
log.info(f"Set properties for file mode: {key} = {value}")
|
||||
|
||||
def set_rules_variables(self, key):
|
||||
if not key in self.fm.filemodes: return
|
||||
|
|
@ -82,6 +104,7 @@ class App(tk.Tk):
|
|||
if len(key) > 0:
|
||||
self.current_mode = key
|
||||
self.set_rules_variables(key)
|
||||
log.debug(f"Selected file mode: {key}")
|
||||
|
||||
def prep(self):
|
||||
self.update_fileview()
|
||||
|
|
@ -89,11 +112,11 @@ class App(tk.Tk):
|
|||
self.set_rules_variables(self.current_mode)
|
||||
|
||||
def run_task(self):
|
||||
print("Task started")
|
||||
log.info("File organization started")
|
||||
self.fm.run_task()
|
||||
|
||||
def run_backup(self):
|
||||
print("Backup started")
|
||||
log.info("File backup started")
|
||||
|
||||
def gui(self):
|
||||
self.gui_menu()
|
||||
|
|
@ -159,7 +182,7 @@ class App(tk.Tk):
|
|||
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")
|
||||
button = ttk.Button(box, text="Reset", command=self.reset_config)
|
||||
button.grid(column=1, row=0, pady=5)
|
||||
|
||||
box.pack(side=tk.TOP, fill=tk.X)
|
||||
|
|
@ -225,5 +248,6 @@ class App(tk.Tk):
|
|||
return frame
|
||||
|
||||
if __name__ == "__main__":
|
||||
setup_log()
|
||||
app = App()
|
||||
app.mainloop()
|
||||
|
|
@ -11,28 +11,28 @@
|
|||
"action": "ignore",
|
||||
"active": true,
|
||||
"destination": "~/Pictures/",
|
||||
"extensions": ["jpg", "jpeg", "png", "gif", "webp"],
|
||||
"extensions": ["jpg", "jpeg", "png", "gif", "bmp", "psd", "raw", "webp"],
|
||||
"name": "Images"
|
||||
},
|
||||
"audio": {
|
||||
"action": "ignore",
|
||||
"active": true,
|
||||
"destination": "~/Music/",
|
||||
"extensions": ["wav", "mp3", "ogg"],
|
||||
"extensions": ["wav", "mp3", "ogg", "flac", "wma", "aiff", "aac"],
|
||||
"name": "Audio"
|
||||
},
|
||||
"video": {
|
||||
"action": "ignore",
|
||||
"active": true,
|
||||
"destination": "~/Videos/",
|
||||
"extensions": ["avi", "mpeg", "mp4", "webm"],
|
||||
"extensions": ["avi", "mpeg", "mp4", "mov", "mkv", "ogv", "webm"],
|
||||
"name": "Video"
|
||||
},
|
||||
"document": {
|
||||
"action": "ignore",
|
||||
"active": true,
|
||||
"destination": "~/Documents/",
|
||||
"extensions": ["txt", "doc", "docx", "pdf"],
|
||||
"extensions": ["txt", "doc", "docx", "pdf", "rtf"],
|
||||
"name": "Documents"
|
||||
},
|
||||
"data": {
|
||||
|
|
@ -46,14 +46,14 @@
|
|||
"action": "ignore",
|
||||
"active": true,
|
||||
"destination": "~/Downloads/",
|
||||
"extensions": ["exe", "msi"],
|
||||
"extensions": ["exe", "msi", "elf"],
|
||||
"name": "Programs"
|
||||
},
|
||||
"archive": {
|
||||
"action": "ignore",
|
||||
"active": true,
|
||||
"destination": "~/Downloads/",
|
||||
"extensions": ["zip", "rar", "gz"],
|
||||
"extensions": ["zip", "rar", "tar", "iso", "gz", "lz", "rz", "7z", "dmg"],
|
||||
"name": "Archives"
|
||||
},
|
||||
"other": {
|
||||
|
|
@ -63,6 +63,5 @@
|
|||
"extensions": [],
|
||||
"name": "Other"
|
||||
}
|
||||
},
|
||||
"version": 1
|
||||
}
|
||||
}
|
||||
|
|
@ -4,7 +4,9 @@ __author__ = "Gull"
|
|||
|
||||
import os
|
||||
import shutil
|
||||
import logging as log
|
||||
import utils as ut
|
||||
import send2trash as s2t
|
||||
|
||||
debug_mode = True
|
||||
|
||||
|
|
@ -61,6 +63,9 @@ class Manager:
|
|||
|
||||
def run_task(self):
|
||||
self.match_file_types() # Updates file types dict
|
||||
log.info(f"Now processing {len(self.filedata)} files")
|
||||
if debug_mode:
|
||||
log.warning("Debug mode is enabled; file actions will be ignored")
|
||||
for k, v in self.filedata.items():
|
||||
fullpath = os.path.join(self.dir, k)
|
||||
if os.path.exists(fullpath):
|
||||
|
|
@ -79,30 +84,23 @@ class Manager:
|
|||
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:
|
||||
src, dst = ut.parse_dir(src), ut.parse_dir(dst)
|
||||
log.info(f"Moved file: {src} > {dst}")
|
||||
if not debug_mode:
|
||||
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:
|
||||
src, dst = ut.parse_dir(src), ut.parse_dir(dst)
|
||||
log.info(f"Copied file: {src} > {dst}")
|
||||
if not debug_mode:
|
||||
shutil.copy2(src, dst)
|
||||
|
||||
def delete(src):
|
||||
src = parse_dir(src)
|
||||
if debug_mode:
|
||||
print(f"Delete: {src}")
|
||||
else:
|
||||
os.remove(src)
|
||||
src = ut.parse_dir(src)
|
||||
log.info(f"Deleted file: {src}")
|
||||
if not debug_mode:
|
||||
try:
|
||||
s2t.send2trash(src)
|
||||
except s2t.TrashPermissionError:
|
||||
pass
|
||||
29
utils.py
29
utils.py
|
|
@ -2,8 +2,10 @@
|
|||
|
||||
__author__ = "Gull"
|
||||
|
||||
import os
|
||||
import time
|
||||
import json
|
||||
import appdirs as ad
|
||||
|
||||
KILOBYTES = 1024
|
||||
|
||||
|
|
@ -20,13 +22,13 @@ def format_bytes(bytes):
|
|||
if bytes < units["KB"]:
|
||||
return f"{bytes} B"
|
||||
elif units["KB"] <= bytes < units["MB"]:
|
||||
return f"{(bytes / units["KB"]):.2f} KB"
|
||||
return f"{(bytes / units['KB']):.2f} KB"
|
||||
elif units["MB"] <= bytes < units["GB"]:
|
||||
return f"{(bytes / units["MB"]):.2f} MB"
|
||||
return f"{(bytes / units['MB']):.2f} MB"
|
||||
elif units["GB"] <= bytes < units["TB"]:
|
||||
return f"{(bytes / units["GB"]):.2f} GB"
|
||||
return f"{(bytes / units['GB']):.2f} GB"
|
||||
elif units["TB"] <= bytes:
|
||||
return f"{(bytes / units["TB"]):.2f} TB"
|
||||
return f"{(bytes / units['TB']):.2f} TB"
|
||||
|
||||
def format_date(timestamp):
|
||||
"""Returns a time string (ISO 8601) from the given integer timestamp."""
|
||||
|
|
@ -41,4 +43,21 @@ def load_json_file(filepath):
|
|||
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)
|
||||
json.dump(data, f, sort_keys=True, indent=None if raw else 2)
|
||||
|
||||
def get_user_dir(dir=""):
|
||||
"""Returns the joined user directory."""
|
||||
return os.path.join(os.path.expanduser("~"), dir)
|
||||
|
||||
def get_appdata_dir(dir=""):
|
||||
"""Returns the joined appdata directory."""
|
||||
return os.path.join(ad.user_data_dir(None, False), dir)
|
||||
|
||||
def parse_dir(dir=""):
|
||||
"""Checks if a directory exists, and if it is special."""
|
||||
if dir[0] == "~": # Denotes the current user directory
|
||||
dir = get_user_dir(dir.lstrip("~/"))
|
||||
elif dir[0] == "%": # Denotes the local appdata directory
|
||||
dir = get_appdata_dir(dir.lstrip("%/"))
|
||||
|
||||
return dir
|
||||
Loading…
Add table
Add a link
Reference in a new issue