Improved directory structure; updated readme
This commit is contained in:
parent
d4d5096f1f
commit
d99c5d2f23
11 changed files with 111 additions and 31 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -5,3 +5,4 @@ venv_linux/
|
|||
build/
|
||||
dist/
|
||||
Finch Filer.spec
|
||||
test.bat
|
||||
|
|
|
|||
52
README.md
52
README.md
|
|
@ -1,10 +1,10 @@
|
|||
# Finch Filer V1.0.0 beta
|
||||
# Finch Filer V1.0.1
|
||||
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
A simple and humble file sorter app, built with the Python TKinter library. It can automatically move, copy, or delete files from a given directory, based on file types. For example, maybe your Downloads folder is cluttered with a bunch of useless files, but you want to keep the image files by moving them into your Pictures folder. This app can help you move the images and delete the junk, all in one click (after a bit of setup).
|
||||
A simple and humble file sorter app, built with the Python TKinter library. It can automatically move, copy, or delete files from a given directory, based on file types. For example, maybe your Downloads folder is cluttered with a bunch of useless files, but you want to keep all image files by moving them into your Pictures folder. This app can help you move the images and delete the junk, all in one click (after a bit of setup).
|
||||
|
||||
Other use cases:
|
||||
|
||||
|
|
@ -14,7 +14,7 @@ Other use cases:
|
|||
|
||||
- Moving only files that contain the name "invoice"
|
||||
|
||||
This is my first real Python project, after many unimportant scripts and experiments. I really needed a project like this in my portfolio, even if it's not truly amazing.
|
||||
This is my first real Python project, after many unimportant scripts and experiments. I really needed a project like this in my portfolio, even if it's not truly amazing. Expect some roughness here and there!
|
||||
|
||||
## Features
|
||||
|
||||
|
|
@ -24,10 +24,24 @@ This is my first real Python project, after many unimportant scripts and experim
|
|||
|
||||
- Save your file rules configuration for future use
|
||||
|
||||
- Advanced: Create an automated task for scheduled file sorting
|
||||
|
||||
## Usage
|
||||
|
||||
You can easily launch the app on Windows by entering into the "Finch Filer.exe" executable.
|
||||
|
||||
Alternatively, open your terminal at the main directory (ensure that Python is installed).
|
||||
|
||||
If this is your first time, you may need to install a few dependencies:
|
||||
|
||||
`pip install -r require_user.txt`
|
||||
|
||||
Now you can launch the app:
|
||||
|
||||
`python finch_filer_gui.py`
|
||||
|
||||
|
||||
|
||||
By default, the first thing you'll see is a list of all files in your Downloads directory. You can switch to a directory of your choice by going to File -> Open Directory. Currently, this app displays only items in the chosen directory and not nested ones. You can inspect this list, as well as sort by date and size by clicking on the column headers.
|
||||
|
||||
Importantly, you'll want to set up file rules if you want things to happen. Select the Rules tab. You'll see a list of selectable generic file types, and options for each one. This is how you can filter out which file types to keep and which ones to delete, for example. Note that the type All Files overrides all other types, unless its action is set to "Ignore".
|
||||
|
|
@ -36,18 +50,42 @@ For moving and copying all files of a given type, you can set the action as desi
|
|||
|
||||
When you are ready, go back to the Files tab and click on the Start Task button. The sorter will do its job, and a summary will be shown at the end.
|
||||
|
||||
For advanced usage, you can use the command line mode by opening your terminal at this directory and entering:
|
||||
|
||||
`python script.py`
|
||||
|
||||
This guide is incomplete. More info will be added later.
|
||||
For advanced usage, you can use the command line mode. Open your terminal at the main directory, and enter:
|
||||
|
||||
`python finch_filer_cli.py`
|
||||
|
||||
By default, it will use the saved settings from the app to determine how files should be sorted. There are a few flags if you want other options:
|
||||
|
||||
```
|
||||
-h, --help show this help message and exit
|
||||
-s, --source SOURCE source directory (default: User Downloads)
|
||||
-r, --rules RULES config file (default: Same as app setting)
|
||||
-m, --mode MODE action for all files (move, copy, delete)
|
||||
-d, --debug enables debug mode and ignores file actions
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
`python finch_filer_cli.py -s ~/Documents/Temp -m delete`
|
||||
|
||||
Hint: You can use `~/` as an alias for your user directory.
|
||||
|
||||
You can automate this task by having this command in a batch, shell, or bash script. This is useful if you want to periodically clean up any given directory.
|
||||
|
||||
## About
|
||||
|
||||
thomas.j.wilc@gmail.com
|
||||
Email: thomas.j.wilc@gmail.com
|
||||
|
||||
## Changelog
|
||||
|
||||
1.0.1
|
||||
|
||||
- Improved directory structure
|
||||
|
||||
- Changed scripts available at project root
|
||||
|
||||
1.0.0
|
||||
|
||||
- Initial public release of Finch Filer
|
||||
|
|
|
|||
2
finch_filer_cli.py
Normal file
2
finch_filer_cli.py
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
from src.finch_filer import script
|
||||
script.run()
|
||||
2
finch_filer_gui.py
Normal file
2
finch_filer_gui.py
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
from src.finch_filer import app
|
||||
app.run()
|
||||
Binary file not shown.
BIN
require_user.txt
Normal file
BIN
require_user.txt
Normal file
Binary file not shown.
2
src/finch_filer/__init__.py
Normal file
2
src/finch_filer/__init__.py
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
__version__ = "1.0.1"
|
||||
__author__ = "Gull"
|
||||
|
|
@ -4,14 +4,15 @@ Frontend GUI that displays a list of files from a folder.
|
|||
File actions (move, copy, or delete) can be set for generic file types.
|
||||
"""
|
||||
|
||||
__name__ = "__main__"
|
||||
__version__ = "1.0.0"
|
||||
__author__ = "Gull"
|
||||
|
||||
import add_root_to_sys_path
|
||||
add_root_to_sys_path.add_to_sys_path(__file__, "src")
|
||||
|
||||
import tkinter as tk
|
||||
import file_manager as fm
|
||||
import logging as log
|
||||
import utils as ut
|
||||
from finch_filer import file_manager as fm
|
||||
from finch_filer import utils as ut
|
||||
from tkinter import ttk
|
||||
from tkinter import messagebox as mb
|
||||
from tkinter import filedialog as fd
|
||||
|
|
@ -41,6 +42,12 @@ def setup():
|
|||
except ImportError:
|
||||
pass
|
||||
|
||||
def run():
|
||||
"""Sets up and runs the app."""
|
||||
setup()
|
||||
app = App()
|
||||
app.mainloop()
|
||||
|
||||
class App(tk.Tk):
|
||||
"""TKinter GUI and related methods."""
|
||||
def __init__(self, width=640, height=480):
|
||||
|
|
@ -454,6 +461,4 @@ class App(tk.Tk):
|
|||
return frame
|
||||
|
||||
if __name__ == "__main__":
|
||||
setup()
|
||||
app = App()
|
||||
app.mainloop()
|
||||
run()
|
||||
|
|
@ -5,8 +5,8 @@ __author__ = "Gull"
|
|||
import os
|
||||
import shutil
|
||||
import logging as log
|
||||
import utils as ut
|
||||
import send2trash as s2t
|
||||
from finch_filer import utils as ut
|
||||
|
||||
debug_mode = False
|
||||
|
||||
|
|
@ -156,8 +156,13 @@ def set_debug_mode(value):
|
|||
|
||||
def move(src, dst):
|
||||
"""Moves a file from a source to a destination."""
|
||||
try:
|
||||
src, dst = ut.parse_dir(src), ut.parse_dir(dst)
|
||||
log.info(f"Moved file: {src} > {dst}")
|
||||
except Exception as error:
|
||||
log.error(f"Invalid source or destination: {src} -> {dst}")
|
||||
print(error)
|
||||
return src, dst
|
||||
|
||||
if not debug_mode:
|
||||
try:
|
||||
shutil.move(src, dst)
|
||||
|
|
@ -166,10 +171,18 @@ def move(src, dst):
|
|||
print(error)
|
||||
return src, dst
|
||||
|
||||
log.info(f"Moved file: {src} > {dst}")
|
||||
return src, dst
|
||||
|
||||
def copy(src, dst):
|
||||
"""Copies a file from a source to a destination."""
|
||||
try:
|
||||
src, dst = ut.parse_dir(src), ut.parse_dir(dst)
|
||||
log.info(f"Copied file: {src} > {dst}")
|
||||
except Exception as error:
|
||||
log.error(f"Invalid source or destination: {src} -> {dst}")
|
||||
print(error)
|
||||
return src, dst
|
||||
|
||||
if not debug_mode:
|
||||
try:
|
||||
shutil.copy2(src, dst)
|
||||
|
|
@ -178,10 +191,18 @@ def copy(src, dst):
|
|||
print(error)
|
||||
return src, dst
|
||||
|
||||
log.info(f"Copied file: {src} > {dst}")
|
||||
return src, dst
|
||||
|
||||
def delete(src):
|
||||
"""Moves a file to the OS trash equivalent."""
|
||||
try:
|
||||
src = ut.parse_dir(src)
|
||||
log.info(f"Deleted file: {src}")
|
||||
except Exception as error:
|
||||
log.error(f"Invalid source: {src}")
|
||||
print(error)
|
||||
return src
|
||||
|
||||
if not debug_mode:
|
||||
try:
|
||||
s2t.send2trash(src)
|
||||
|
|
@ -189,3 +210,6 @@ def delete(src):
|
|||
log.error(f"Failed to delete file: {src}")
|
||||
print(error)
|
||||
return src
|
||||
|
||||
log.info(f"Deleted file: {src}")
|
||||
return src
|
||||
|
|
@ -2,11 +2,14 @@
|
|||
|
||||
__author__ = "Gull"
|
||||
|
||||
import add_root_to_sys_path
|
||||
add_root_to_sys_path.add_to_sys_path(__file__, "src")
|
||||
|
||||
import sys
|
||||
import logging as log
|
||||
import utils as ut
|
||||
import file_manager as fm
|
||||
from argparse import ArgumentParser as ap
|
||||
from finch_filer import file_manager as fm
|
||||
from finch_filer import utils as ut
|
||||
|
||||
LOG_PATH = "%/Gullbase/FinchFiler/script.log"
|
||||
SOURCE_PATH = "~/Downloads"
|
||||
|
|
@ -18,7 +21,7 @@ def setup_log():
|
|||
log.getLogger().addHandler(log.StreamHandler(sys.stdout)) # Console
|
||||
log.info("Script started")
|
||||
|
||||
def run():
|
||||
def get_parser():
|
||||
parser = ap(prog="Finch Filer",
|
||||
description="Moves, copies, or deletes files from a source "
|
||||
"directory.",
|
||||
|
|
@ -28,12 +31,14 @@ def run():
|
|||
parser.add_argument("-r", "--rules", default=RULES_PATH,
|
||||
help="config file (default: Same as app setting)")
|
||||
parser.add_argument("-m", "--mode", default="default",
|
||||
help="action for all files (move, copy, delete, "
|
||||
"ignore)")
|
||||
help="action for all files (move, copy, delete)")
|
||||
parser.add_argument("-d", "--debug", action="store_true",
|
||||
help="enables debug mode and ignores file actions")
|
||||
|
||||
args = parser.parse_args()
|
||||
return parser
|
||||
|
||||
def run():
|
||||
args = get_parser().parse_args()
|
||||
source = ut.parse_dir(args.source, True)
|
||||
rules = ut.parse_dir(args.rules, True)
|
||||
mode = args.mode
|
||||
|
|
@ -65,4 +70,5 @@ def run():
|
|||
mgr.run_task()
|
||||
log.info("Script finished")
|
||||
|
||||
run()
|
||||
if __name__ == "__main__":
|
||||
run()
|
||||
|
|
@ -59,13 +59,13 @@ def parse_dir(path="", ignore_mkdir=False):
|
|||
path = pathlib.Path(path).expanduser()
|
||||
elif path[0] == "%": # Denotes the local appdata directory
|
||||
path = pathlib.Path(ad.user_data_dir(None, False)) / path.lstrip("%/")
|
||||
elif path[0] == "#": # Denotes the project dev directory
|
||||
elif path[0] == "#": # Denotes the project root directory
|
||||
try:
|
||||
base_path = sys._MEIPASS # For PyInstaller
|
||||
except Exception:
|
||||
base_path = os.path.dirname(__file__)
|
||||
base_path = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
path = pathlib.Path(base_path) / path.lstrip("#/")
|
||||
path = pathlib.Path(base_path).parent.parent / path.lstrip("#/")
|
||||
else:
|
||||
path = pathlib.Path(path)
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue