From 7c635fed24bba638f10a73fe39134519ecd675bf Mon Sep 17 00:00:00 2001 From: Leonard Kugis Date: Tue, 21 Mar 2023 23:49:42 +0100 Subject: Split util and tmsu functions --- file-tagger.py | 119 +++------------------------------------------------------ gui.py | 9 +++-- tmsu.py | 71 ++++++++++++++++++++++++++++++++++ util.py | 79 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 161 insertions(+), 117 deletions(-) create mode 100644 tmsu.py create mode 100644 util.py diff --git a/file-tagger.py b/file-tagger.py index 9812f62..82aacf7 100644 --- a/file-tagger.py +++ b/file-tagger.py @@ -5,119 +5,8 @@ from gui import GuiMain, GuiImage, GuiTag import cv2 import logging import magic -import subprocess -import re -import platform -import readline - -''' -Fetch input prompt with prefilled text. - -Parameters: -prompt: Prompt message. -text: Prefilled input. -''' -def input_with_prefill(prompt, text): - def hook(): - readline.insert_text(text) - readline.redisplay() - readline.set_pre_input_hook(hook) - result = input(prompt) - readline.set_pre_input_hook() - return result - -''' -Checks if the given string is a valid path. - -Parameters: -string: String to be checked. -''' -def dir_path(string): - if os.path.isdir(string): - return string - else: - raise NotADirectoryError(string) - -''' -Opens the given file with the platform default handler. - -Parameters: -file: Path to the file. -''' -def open_system(file): - if platform.system() == 'Darwin': # macOS - subprocess.call(('open', file)) - elif platform.system() == 'Windows': # Windows - os.startfile(file) - else: # linux variants - subprocess.call(('xdg-open', file)) - -''' -Initializes TMSU in a given directory. -Does nothing, if it is already initialized. - -Parameters: -base: Directory to initialize. -''' -def tmsu_init(base): - logger = logging.getLogger(__name__) - if not os.path.exists(os.path.join(base, ".tmsu")): - logger.info("TMSU database does not exist, creating ...") - proc = subprocess.Popen(["tmsu", "init"], cwd=base) - proc.wait() - logger.debug("TMSU returncode: {}".format(proc.returncode)) - if proc.returncode != 0: - logger.error("Could not initialize TMSU database.") - return False - return True - -''' -Reads the tags for the specified file. - -Parameters: -base: Base directory for the database. -file: File to get the tags for. -''' -def tmsu_tags(base, file): - logger = logging.getLogger(__name__) - logger.debug("Getting existing tags for file {}".format(file)) - tags = set() - proc = subprocess.Popen(["tmsu", "tags", os.path.relpath(file, base)], cwd=base, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - proc.wait() - logger.debug("TMSU returncode: {}".format(proc.returncode)) - if proc.returncode == 0: - ret = proc.stdout.read().decode() - logger.debug("Raw TMSU tags: {}".format(ret)) - tags.update(re.split("\s", ret.split(":")[1])[1:-1]) - else: - logger.error("Could not get tags for file {}".format(file)) - return tags - -''' -Sets tags for the specified file. - -Parameters: -base: Base directory for the database. -file: File to set the tags for. -tags: Tags to set. -untag: If True, it will remove all existing tags first. If False, it will just append new tags. -''' -def tmsu_tag(base, file, tags, untag=True): - logger = logging.getLogger(__name__) - if untag: - logger.debug("Untagging file") - proc = subprocess.Popen(["tmsu", "untag", "--all", os.path.relpath(file, base)], cwd=base, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - proc.wait() - if proc.returncode != 0: - logger.error("Could not untag file {}".format(file)) - if tags: - logger.debug("Writing tags {}".format(tags)) - proc = subprocess.Popen(["tmsu", "tag", os.path.relpath(file, base)] + list(tags), cwd=base, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - proc.wait() - if proc.returncode != 0: - logger.error("Could not write tags to file {}".format(file)) - else: - logger.info("Tags are empty, ignoring") +from tmsu import * +from util import * ''' Walk over all files for the given base directory and all subdirectories recursively. @@ -199,7 +88,7 @@ def walk(args): elif ret[0] == GuiTag.RETURN_ABORT: return - if not args["gui_tag"]: + if ((not args["gui_tag"]) and (not args["skip_prompt"])): tags = set(input_with_prefill("\nTags for file {}:\n".format(file_path), ','.join(tags)).split(",")) logger.info("Tagging {}".format(tags)) @@ -215,6 +104,7 @@ if __name__ == "__main__": parser.add_argument('--predict-images-top', nargs='?', const=1, default=10, type=int, help='Defines how many top prediction keywords should be used (default: %(default)s)') parser.add_argument('--gui-tag', nargs='?', const=1, default=False, type=bool, help='Show GUI for tagging (default: %(default)s)') parser.add_argument('--open-system', nargs='?', const=1, default=False, type=bool, help='Open all files with system default (default: %(default)s)') + parser.add_argument('-s', '--skip-prompt', nargs='?', const=1, default=False, type=bool, help='Skip prompt for file tags (default: %(default)s)') parser.add_argument('-i', '--index', nargs='?', const=1, default=0, type=int, help='Start tagging at the given file index (default: %(default)s)') parser.add_argument('-v', '--verbose', action="count", default=0, help="Verbosity level") args = parser.parse_args() @@ -237,6 +127,7 @@ if __name__ == "__main__": "predict_images_top": args.predict_images_top, "gui_tag": args.gui_tag, "open_system": args.open_system, + "skip_prompt": args.skip_prompt, "index": args.index, "verbosity": args.verbose } diff --git a/gui.py b/gui.py index d84aa0a..8ab062d 100644 --- a/gui.py +++ b/gui.py @@ -16,6 +16,7 @@ class GuiMain(object): self.__predict_images_top = StringVar(self.__master, value=str(args["predict_images_top"])) self.__gui_tag = BooleanVar(self.__master, value=args["gui_tag"]) self.__open_system = BooleanVar(self.__master, value=args["open_system"]) + self.__skip_prompt = BooleanVar(self.__master, value=args["skip_prompt"]) self.__index = StringVar(self.__master, value=str(args["index"])) validate_number = (self.__master.register(self.__validate_number)) @@ -31,9 +32,10 @@ class GuiMain(object): Entry(self.__master, textvariable=self.__predict_images_top, validate='all', validatecommand=(validate_number, '%P')).grid(row=3, column=1, columnspan=1) Checkbutton(self.__master, text="Show GUI for tagging", variable=self.__gui_tag).grid(row=4, column=0, columnspan=4, sticky=W) Checkbutton(self.__master, text="Open all files with system default", variable=self.__open_system).grid(row=5, column=0, columnspan=4, sticky=W) - Label(self.__master, text="Start at index:").grid(row=6, column=0) - Entry(self.__master, textvariable=self.__index, validate='all', validatecommand=(validate_number, '%P')).grid(row=6, column=1, columnspan=1) - Button(self.__master, text="Start", command=self.__master.destroy).grid(row=7, column=0, columnspan=4) + Checkbutton(self.__master, text="Skip prompt for file tags", variable=self.__skip_prompt).grid(row=6, column=0, columnspan=4, sticky=W) + Label(self.__master, text="Start at index:").grid(row=7, column=0) + Entry(self.__master, textvariable=self.__index, validate='all', validatecommand=(validate_number, '%P')).grid(row=7, column=1, columnspan=1) + Button(self.__master, text="Start", command=self.__master.destroy).grid(row=8, column=0, columnspan=4) def loop(self): self.__master.mainloop() @@ -44,6 +46,7 @@ class GuiMain(object): self.__args["predict_images_top"] = int(self.__predict_images_top.get()) self.__args["gui_tag"] = self.__gui_tag.get() self.__args["open_system"] = self.__open_system.get() + self.__args["skip_prompt"] = self.__skip_prompt.get() self.__args["index"] = int(self.__index.get()) return self.__args diff --git a/tmsu.py b/tmsu.py new file mode 100644 index 0000000..4bd8946 --- /dev/null +++ b/tmsu.py @@ -0,0 +1,71 @@ +import subprocess +import re +import logging +import os + +''' +Initializes TMSU in a given directory. +Does nothing, if it is already initialized. + +Parameters: +base: Directory to initialize. +''' +def tmsu_init(base): + logger = logging.getLogger(__name__) + if not os.path.exists(os.path.join(base, ".tmsu")): + logger.info("TMSU database does not exist, creating ...") + proc = subprocess.Popen(["tmsu", "init"], cwd=base) + proc.wait() + logger.debug("TMSU returncode: {}".format(proc.returncode)) + if proc.returncode != 0: + logger.error("Could not initialize TMSU database.") + return False + return True + +''' +Reads the tags for the specified file. + +Parameters: +base: Base directory for the database. +file: File to get the tags for. +''' +def tmsu_tags(base, file): + logger = logging.getLogger(__name__) + logger.debug("Getting existing tags for file {}".format(file)) + tags = set() + proc = subprocess.Popen(["tmsu", "tags", os.path.relpath(file, base)], cwd=base, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + proc.wait() + logger.debug("TMSU returncode: {}".format(proc.returncode)) + if proc.returncode == 0: + ret = proc.stdout.read().decode() + logger.debug("Raw TMSU tags: {}".format(ret)) + tags.update(re.split("\s", ret.split(":")[1])[1:-1]) + else: + logger.error("Could not get tags for file {}".format(file)) + return tags + +''' +Sets tags for the specified file. + +Parameters: +base: Base directory for the database. +file: File to set the tags for. +tags: Tags to set. +untag: If True, it will remove all existing tags first. If False, it will just append new tags. +''' +def tmsu_tag(base, file, tags, untag=True): + logger = logging.getLogger(__name__) + if untag: + logger.debug("Untagging file") + proc = subprocess.Popen(["tmsu", "untag", "--all", os.path.relpath(file, base)], cwd=base, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + proc.wait() + if proc.returncode != 0: + logger.error("Could not untag file {}".format(file)) + if tags: + logger.debug("Writing tags {}".format(tags)) + proc = subprocess.Popen(["tmsu", "tag", os.path.relpath(file, base)] + list(tags), cwd=base, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + proc.wait() + if proc.returncode != 0: + logger.error("Could not write tags to file {}".format(file)) + else: + logger.info("Tags are empty, ignoring") \ No newline at end of file diff --git a/util.py b/util.py new file mode 100644 index 0000000..2bf4ff8 --- /dev/null +++ b/util.py @@ -0,0 +1,79 @@ +import subprocess +import logging +import cv2 +import platform +import readline +import os + +def image_resize(image, width = None, height = None, inter = cv2.INTER_AREA): + # initialize the dimensions of the image to be resized and + # grab the image size + dim = None + (h, w) = image.shape[:2] + + # if both the width and height are None, then return the + # original image + if width is None and height is None: + return image + + # check to see if the width is None + if width is None: + # calculate the ratio of the height and construct the + # dimensions + r = height / float(h) + dim = (int(w * r), height) + + # otherwise, the height is None + else: + # calculate the ratio of the width and construct the + # dimensions + r = width / float(w) + dim = (width, int(h * r)) + + # resize the image + resized = cv2.resize(image, dim, interpolation = inter) + + # return the resized image + return resized + +''' +Fetch input prompt with prefilled text. + +Parameters: +prompt: Prompt message. +text: Prefilled input. +''' +def input_with_prefill(prompt, text): + def hook(): + readline.insert_text(text) + readline.redisplay() + readline.set_pre_input_hook(hook) + result = input(prompt) + readline.set_pre_input_hook() + return result + +''' +Checks if the given string is a valid path. + +Parameters: +string: String to be checked. +''' +def dir_path(string): + if os.path.isdir(string): + return string + else: + raise NotADirectoryError(string) + +''' +Opens the given file with the platform default handler. + +Parameters: +file: Path to the file. +''' +def open_system(file): + if platform.system() == 'Darwin': # macOS + subprocess.call(('open', file)) + elif platform.system() == 'Windows': # Windows + os.startfile(file) + else: # linux variants + subprocess.call(('xdg-open', file)) \ No newline at end of file -- cgit v1.2.1