Added utils; minor progress in app
This commit is contained in:
parent
9d38821726
commit
f62008028a
4 changed files with 134 additions and 31 deletions
13
README.txt
13
README.txt
|
|
@ -1 +1,12 @@
|
||||||
A simple app that manages your downloads folder.
|
A simple app that manages your downloads folder.
|
||||||
|
|
||||||
|
Features:
|
||||||
|
- File list view, separated by type
|
||||||
|
- File name, date modified, size
|
||||||
|
- Buttons
|
||||||
|
- Start Task, Refresh, Backup
|
||||||
|
- Status bar
|
||||||
|
- Rules manager
|
||||||
|
- Per file type: Move to dir, copy to dir, delete, or ignore
|
||||||
|
- Custom define file types
|
||||||
|
- Save and load rules config
|
||||||
85
app.py
85
app.py
|
|
@ -4,12 +4,15 @@ __name__ = "__main__"
|
||||||
__author__ = "Gull"
|
__author__ = "Gull"
|
||||||
|
|
||||||
import tkinter as tk
|
import tkinter as tk
|
||||||
from tkinter import ttk # Modern widgets
|
|
||||||
import file_manager as fm
|
import file_manager as fm
|
||||||
|
import utils as ut
|
||||||
|
from tkinter import ttk
|
||||||
|
from tkinter.messagebox import showinfo
|
||||||
|
|
||||||
debug_mode = False
|
debug_mode = False
|
||||||
|
|
||||||
def set_debug_mode(value):
|
def set_debug_mode(value):
|
||||||
|
global debug_mode
|
||||||
if type(value) == None:
|
if type(value) == None:
|
||||||
debug_mode = not debug_mode
|
debug_mode = not debug_mode
|
||||||
else:
|
else:
|
||||||
|
|
@ -19,6 +22,7 @@ class App(tk.Tk):
|
||||||
def __init__(self, width=600, height=400):
|
def __init__(self, width=600, height=400):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.title("Download Utils")
|
self.title("Download Utils")
|
||||||
|
self.option_add('*tearOff', tk.FALSE)
|
||||||
self.fm = fm.Manager()
|
self.fm = fm.Manager()
|
||||||
self.gui()
|
self.gui()
|
||||||
|
|
||||||
|
|
@ -30,17 +34,27 @@ class App(tk.Tk):
|
||||||
|
|
||||||
self.geometry(f"{width}x{height}+{center_x}+{center_y}")
|
self.geometry(f"{width}x{height}+{center_x}+{center_y}")
|
||||||
|
|
||||||
def update_file_list(self):
|
def update_fileview(self):
|
||||||
for n in range(self.listbox_file.size(), 0, -1):
|
self.fmgr = fm.Manager()
|
||||||
self.listbox_file.delete(n - 1)
|
self.fmgr.set_directory(self.fmgr.get_directory())
|
||||||
self.fm.update_file_list()
|
self.fmgr.update_file_data()
|
||||||
for v in self.fm.filelist:
|
|
||||||
self.listbox_file.insert(tk.END, v)
|
while len(self.fileview.get_children()) > 0:
|
||||||
|
self.fileview.delete(self.fileview.get_children()[-1])
|
||||||
|
|
||||||
|
for k, v in self.fmgr.filedata.items():
|
||||||
|
values = (k, str(ut.format_date(v["time"])),
|
||||||
|
str(ut.format_bytes(v["size"])))
|
||||||
|
self.fileview.insert("", tk.END, k, values=values)
|
||||||
|
|
||||||
def gui(self):
|
def gui(self):
|
||||||
self.gui_menu()
|
self.gui_menu()
|
||||||
self.gui_side()
|
|
||||||
self.gui_main()
|
self.book = ttk.Notebook(self)
|
||||||
|
self.book.add(self.gui_files(), text="Files")
|
||||||
|
self.book.add(self.gui_rules(), text="Rules")
|
||||||
|
|
||||||
|
self.book.pack(expand=True, fill=tk.BOTH)
|
||||||
|
|
||||||
def gui_menu(self):
|
def gui_menu(self):
|
||||||
a_menu = tk.Menu(self) # First arg is always the parent
|
a_menu = tk.Menu(self) # First arg is always the parent
|
||||||
|
|
@ -64,25 +78,52 @@ class App(tk.Tk):
|
||||||
menu=a_menu_settings,
|
menu=a_menu_settings,
|
||||||
underline=0
|
underline=0
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def gui_files(self):
|
||||||
|
frame = ttk.Frame(self.book)
|
||||||
|
|
||||||
|
box = ttk.Frame(frame)
|
||||||
|
|
||||||
|
button = ttk.Button(box, text="Start 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.grid(column=2, row=0, pady=5)
|
||||||
|
|
||||||
|
box.pack(side=tk.TOP, fill=tk.X)
|
||||||
|
|
||||||
|
self.fileview_columns = ("Name", "Last Modified", "Size")
|
||||||
|
self.fileview = ttk.Treeview(frame, columns=self.fileview_columns,
|
||||||
|
show="headings")
|
||||||
|
|
||||||
def gui_side(self):
|
for v in self.fileview_columns:
|
||||||
a_side = ttk.Frame(self, width=80, style="TLabel")
|
self.fileview.heading(v, text=v)
|
||||||
a_side.pack(side=tk.LEFT, fill=tk.Y)
|
self.fileview.column(v, width=100, anchor=tk.W)
|
||||||
|
|
||||||
tk_style = ttk.Style(self)
|
sbar = ttk.Scrollbar(frame, orient=tk.VERTICAL,
|
||||||
tk_style.configure("TLabel", background="#bbbbbb")
|
command=self.fileview.yview)
|
||||||
|
self.fileview.configure(yscrollcommand=sbar.set)
|
||||||
|
|
||||||
def gui_main(self):
|
self.update_fileview()
|
||||||
a_content = ttk.Frame(self)
|
|
||||||
|
|
||||||
a_button = ttk.Button(a_content, text="Refresh", command=self.update_file_list)
|
self.fileview.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
|
||||||
a_button.pack(side=tk.TOP)
|
sbar.pack(side=tk.RIGHT, fill=tk.Y)
|
||||||
|
|
||||||
self.listbox_file = tk.Listbox(a_content, height=20)
|
return frame
|
||||||
self.update_file_list()
|
|
||||||
self.listbox_file.pack(padx=10, pady=10, side=tk.LEFT, expand=True, fill=tk.BOTH)
|
def gui_rules(self):
|
||||||
|
frame = ttk.Frame(self.book)
|
||||||
|
|
||||||
a_content.pack(side=tk.LEFT, expand=True, fill=tk.BOTH)
|
# Display a simple panel on the left having file meta types
|
||||||
|
|
||||||
|
# Mode:
|
||||||
|
# Target dir:
|
||||||
|
# File extensions:
|
||||||
|
|
||||||
|
return frame
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
app = App()
|
app = App()
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
"""File manager for the app."""
|
"""File manager and organizer for the app."""
|
||||||
|
|
||||||
__author__ = "Gull"
|
__author__ = "Gull"
|
||||||
|
|
||||||
|
|
@ -7,18 +7,38 @@ import json
|
||||||
|
|
||||||
class Manager:
|
class Manager:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.dir = self.get_directory()
|
self.dir = os.path.expanduser("~") # Default directory
|
||||||
self.filelist = []
|
self.filedata = dict()
|
||||||
|
self.filetypes = {
|
||||||
|
"images": ["jpg", "jpeg", "png", "gif", "webp"],
|
||||||
|
"audio": ["wav", "mp3", "ogg"],
|
||||||
|
"video": ["wmv", "mpg", "mpeg", "avi"],
|
||||||
|
"text": ["txt", "doc", "docx"],
|
||||||
|
"data": ["csv", "json"],
|
||||||
|
"programs": ["exe", "msi"],
|
||||||
|
"archives": ["zip", "gz", "rar"],
|
||||||
|
"other": []
|
||||||
|
}
|
||||||
|
|
||||||
def get_directory(self):
|
def get_directory(self, target="Downloads"):
|
||||||
dir = os.path.expanduser("~")
|
dir = os.path.expanduser("~")
|
||||||
dir = os.path.join(dir, "Downloads")
|
dir = os.path.join(dir, target)
|
||||||
if os.path.exists(dir): # Needs error handling
|
if os.path.exists(dir): # Needs error handling
|
||||||
return dir
|
return dir
|
||||||
|
|
||||||
def update_file_list(self):
|
def set_directory(self, dir):
|
||||||
self.filelist.clear()
|
if os.path.exists(dir):
|
||||||
|
self.dir = dir
|
||||||
|
|
||||||
|
def modify_type_list(self, key, values):
|
||||||
|
if key in self.filetypes:
|
||||||
|
self.filetypes[key] = list(values)
|
||||||
|
|
||||||
|
def update_file_data(self):
|
||||||
|
self.filedata.clear()
|
||||||
with os.scandir(self.dir) as scan:
|
with os.scandir(self.dir) as scan:
|
||||||
for entry in scan:
|
for entry in scan:
|
||||||
if entry.is_file():
|
if entry.is_file():
|
||||||
self.filelist.append(entry.name)
|
st = entry.stat()
|
||||||
|
data = {"time": st.st_mtime, "size": st.st_size}
|
||||||
|
self.filedata.update({entry.name: data})
|
||||||
31
utils.py
Normal file
31
utils.py
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
"""Utility functions."""
|
||||||
|
|
||||||
|
__author__ = "Gull"
|
||||||
|
|
||||||
|
import time
|
||||||
|
|
||||||
|
KILOBYTES = 1024
|
||||||
|
|
||||||
|
def format_bytes(bytes):
|
||||||
|
"""Return the given bytes as a human friendly KB, MB, GB, or TB string."""
|
||||||
|
units = {
|
||||||
|
"B": float(1),
|
||||||
|
"KB": float(KILOBYTES),
|
||||||
|
"MB": float(KILOBYTES ** 2), # 1,048,576
|
||||||
|
"GB": float(KILOBYTES ** 3), # 1,073,741,824
|
||||||
|
"TB": float(KILOBYTES ** 4) # 1,099,511,627,776
|
||||||
|
}
|
||||||
|
|
||||||
|
if bytes < units["KB"]:
|
||||||
|
return f"{bytes} B"
|
||||||
|
elif units["KB"] <= bytes < units["MB"]:
|
||||||
|
return f"{(bytes / units["KB"]):.2f} KB"
|
||||||
|
elif units["MB"] <= bytes < units["GB"]:
|
||||||
|
return f"{(bytes / units["MB"]):.2f} MB"
|
||||||
|
elif units["GB"] <= bytes < units["TB"]:
|
||||||
|
return f"{(bytes / units["GB"]):.2f} GB"
|
||||||
|
elif units["TB"] <= bytes:
|
||||||
|
return f"{(bytes / units["TB"]):.2f} TB"
|
||||||
|
|
||||||
|
def format_date(timestamp):
|
||||||
|
return time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(timestamp))
|
||||||
Loading…
Add table
Add a link
Reference in a new issue